From e9594c6043b64e4f8b1b86bf4fb5018a129246c6 Mon Sep 17 00:00:00 2001 From: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> Date: Tue, 30 Apr 2024 13:51:59 +0900 Subject: [PATCH 01/10] make remove objects from history templated Signed-off-by: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> --- .../map_based_prediction_node.hpp | 3 +- .../src/map_based_prediction_node.cpp | 93 ++++++++++--------- 2 files changed, 51 insertions(+), 45 deletions(-) diff --git a/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp b/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp index 829c4d6e4a114..f240106caa8b6 100644 --- a/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp +++ b/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp @@ -222,8 +222,7 @@ class MapBasedPredictionNode : public rclcpp::Node PredictedObject getPredictedObjectAsCrosswalkUser(const TrackedObject & object); - void removeOldObjectsHistory( - const double current_time, const TrackedObjects::ConstSharedPtr in_objects); + void cleanupOldStoppedOnGreenTimes(const TrackedObjects::ConstSharedPtr in_objects); LaneletsData getCurrentLanelets(const TrackedObject & object); bool checkCloseLaneletCondition( diff --git a/perception/map_based_prediction/src/map_based_prediction_node.cpp b/perception/map_based_prediction/src/map_based_prediction_node.cpp index 56dc1c2293583..78c48cb49735b 100644 --- a/perception/map_based_prediction/src/map_based_prediction_node.cpp +++ b/perception/map_based_prediction/src/map_based_prediction_node.cpp @@ -585,6 +585,53 @@ bool hasPotentialToReach( return false; } +template <typename T> +std::unordered_set<std::string> removeOldObjectsHistory( + const double current_time, const double buffer_time, std::unordered_map<std::string, std::deque<T>> & target_objects) +{ + std::unordered_set<std::string> invalid_object_id; + for (auto iter = target_objects.begin(); iter != target_objects.end(); ++iter) { + const std::string object_id = iter->first; + std::deque<T> & object_data = iter->second; + + // If object data is empty, we are going to delete the buffer for the obstacle + if (object_data.empty()) { + invalid_object_id.insert(object_id); + continue; + } + + const double latest_object_time = rclcpp::Time(object_data.back().header.stamp).seconds(); + + // Delete Old Objects + if (current_time - latest_object_time > buffer_time) { + invalid_object_id.insert(object_id); + continue; + } + + // Delete old information + while (!object_data.empty()) { + const double post_object_time = rclcpp::Time(object_data.front().header.stamp).seconds(); + if (current_time - post_object_time > buffer_time) { + // Delete Old Position + object_data.pop_front(); + } else { + break; + } + } + + if (object_data.empty()) { + invalid_object_id.insert(object_id); + continue; + } + } + + for (const auto & key : invalid_object_id) { + target_objects.erase(key); + } + + return invalid_object_id; +} + /** * @brief change label for prediction * @@ -916,7 +963,8 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt // Remove old objects information in object history const double objects_detected_time = rclcpp::Time(in_objects->header.stamp).seconds(); - removeOldObjectsHistory(objects_detected_time, in_objects); + removeOldObjectsHistory(objects_detected_time, object_buffer_time_length_, objects_history_); + cleanupOldStoppedOnGreenTimes(in_objects); // result output PredictedObjects output; @@ -1343,49 +1391,8 @@ void MapBasedPredictionNode::updateObjectData(TrackedObject & object) return; } -void MapBasedPredictionNode::removeOldObjectsHistory( - const double current_time, const TrackedObjects::ConstSharedPtr in_objects) +void MapBasedPredictionNode::cleanupOldStoppedOnGreenTimes(const TrackedObjects::ConstSharedPtr in_objects) { - std::vector<std::string> invalid_object_id; - for (auto iter = objects_history_.begin(); iter != objects_history_.end(); ++iter) { - const std::string object_id = iter->first; - std::deque<ObjectData> & object_data = iter->second; - - // If object data is empty, we are going to delete the buffer for the obstacle - if (object_data.empty()) { - invalid_object_id.push_back(object_id); - continue; - } - - const double latest_object_time = rclcpp::Time(object_data.back().header.stamp).seconds(); - - // Delete Old Objects - if (current_time - latest_object_time > object_buffer_time_length_) { - invalid_object_id.push_back(object_id); - continue; - } - - // Delete old information - while (!object_data.empty()) { - const double post_object_time = rclcpp::Time(object_data.front().header.stamp).seconds(); - if (current_time - post_object_time > object_buffer_time_length_) { - // Delete Old Position - object_data.pop_front(); - } else { - break; - } - } - - if (object_data.empty()) { - invalid_object_id.push_back(object_id); - continue; - } - } - - for (const auto & key : invalid_object_id) { - objects_history_.erase(key); - } - for (auto it = stopped_times_against_green_.begin(); it != stopped_times_against_green_.end();) { const bool isDisappeared = std::none_of( in_objects->objects.begin(), in_objects->objects.end(), From 39914e97ed24d928e831e91bb4435ab7454eac87 Mon Sep 17 00:00:00 2001 From: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> Date: Tue, 30 Apr 2024 13:52:49 +0900 Subject: [PATCH 02/10] pre-commit Signed-off-by: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> --- .../map_based_prediction/src/map_based_prediction_node.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/perception/map_based_prediction/src/map_based_prediction_node.cpp b/perception/map_based_prediction/src/map_based_prediction_node.cpp index 78c48cb49735b..04c64eb3edc1f 100644 --- a/perception/map_based_prediction/src/map_based_prediction_node.cpp +++ b/perception/map_based_prediction/src/map_based_prediction_node.cpp @@ -587,7 +587,8 @@ bool hasPotentialToReach( template <typename T> std::unordered_set<std::string> removeOldObjectsHistory( - const double current_time, const double buffer_time, std::unordered_map<std::string, std::deque<T>> & target_objects) + const double current_time, const double buffer_time, + std::unordered_map<std::string, std::deque<T>> & target_objects) { std::unordered_set<std::string> invalid_object_id; for (auto iter = target_objects.begin(); iter != target_objects.end(); ++iter) { @@ -1391,7 +1392,8 @@ void MapBasedPredictionNode::updateObjectData(TrackedObject & object) return; } -void MapBasedPredictionNode::cleanupOldStoppedOnGreenTimes(const TrackedObjects::ConstSharedPtr in_objects) +void MapBasedPredictionNode::cleanupOldStoppedOnGreenTimes( + const TrackedObjects::ConstSharedPtr in_objects) { for (auto it = stopped_times_against_green_.begin(); it != stopped_times_against_green_.end();) { const bool isDisappeared = std::none_of( From 05e5c804d4a8260cc815973d379a26f1e57e8b71 Mon Sep 17 00:00:00 2001 From: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> Date: Tue, 30 Apr 2024 14:00:13 +0900 Subject: [PATCH 03/10] create crosswalk user history Signed-off-by: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> --- .../map_based_prediction_node.hpp | 10 ++++++++++ .../src/map_based_prediction_node.cpp | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp b/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp index f240106caa8b6..e0a9ee51aa30d 100644 --- a/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp +++ b/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp @@ -85,6 +85,12 @@ struct ObjectData Maneuver::UNINITIALIZED}; // output maneuver considering previous one shot maneuvers }; +struct CrosswalkUserData +{ + std_msgs::msg::Header header; + autoware_auto_perception_msgs::msg::TrackedObject tracked_object; +}; + struct LaneletData { lanelet::Lanelet lanelet; @@ -137,6 +143,7 @@ class MapBasedPredictionNode : public rclcpp::Node // Object History std::unordered_map<std::string, std::deque<ObjectData>> objects_history_; std::map<std::pair<std::string, lanelet::Id>, rclcpp::Time> stopped_times_against_green_; + std::unordered_map<std::string, std::deque<CrosswalkUserData>> crosswalk_users_history_; // Lanelet Map Pointers std::shared_ptr<lanelet::LaneletMap> lanelet_map_ptr_; @@ -234,6 +241,9 @@ class MapBasedPredictionNode : public rclcpp::Node void updateObjectsHistory( const std_msgs::msg::Header & header, const TrackedObject & object, const LaneletsData & current_lanelets_data); + void updateCrosswalkUserHistory( + const std_msgs::msg::Header & header, const TrackedObject & object, + const std::string & object_id); std::vector<PredictedRefPath> getPredictedReferencePath( const TrackedObject & object, const LaneletsData & current_lanelets_data, diff --git a/perception/map_based_prediction/src/map_based_prediction_node.cpp b/perception/map_based_prediction/src/map_based_prediction_node.cpp index 04c64eb3edc1f..fdea487eb1e3f 100644 --- a/perception/map_based_prediction/src/map_based_prediction_node.cpp +++ b/perception/map_based_prediction/src/map_based_prediction_node.cpp @@ -967,6 +967,9 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt removeOldObjectsHistory(objects_detected_time, object_buffer_time_length_, objects_history_); cleanupOldStoppedOnGreenTimes(in_objects); + auto invalidated_crosswalk_users = removeOldObjectsHistory( + objects_detected_time, object_buffer_time_length_, crosswalk_users_history_); + // result output PredictedObjects output; output.header = in_objects->header; @@ -1172,6 +1175,19 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt "debug/processing_time_ms", processing_time_ms); } +void MapBasedPredictionNode::updateCrosswalkUserHistory( + const std_msgs::msg::Header & header, const TrackedObject & object, const std::string & object_id) +{ + CrosswalkUserData crosswalk_user_data; + crosswalk_user_data.header = header; + crosswalk_user_data.tracked_object = object; + if (crosswalk_users_history_.count(object_id) == 0) { + crosswalk_users_history_.emplace(object_id, std::deque<CrosswalkUserData>{crosswalk_user_data}); + } else { + crosswalk_users_history_.at(object_id).push_back(crosswalk_user_data); + } +} + bool MapBasedPredictionNode::doesPathCrossAnyFence(const PredictedPath & predicted_path) { const lanelet::ConstLineStrings3d & all_fences = From 1823b7f2f7a750e851c7ad07ea2dacd54f166f08 Mon Sep 17 00:00:00 2001 From: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> Date: Tue, 30 Apr 2024 14:15:33 +0900 Subject: [PATCH 04/10] use crosswalk user history Signed-off-by: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> --- .../config/map_based_prediction.param.yaml | 3 + .../map_based_prediction_node.hpp | 8 +- .../src/map_based_prediction_node.cpp | 90 ++++++++++++++++++- 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/perception/map_based_prediction/config/map_based_prediction.param.yaml b/perception/map_based_prediction/config/map_based_prediction.param.yaml index f8ad371ab92a6..c825e2c3776da 100644 --- a/perception/map_based_prediction/config/map_based_prediction.param.yaml +++ b/perception/map_based_prediction/config/map_based_prediction.param.yaml @@ -27,6 +27,9 @@ timeout_set_for_no_intention_to_walk: [1.0, 0.0] # [s] values of map # parameter for shoulder lane prediction prediction_time_horizon_rate_for_validate_shoulder_lane_length: 0.8 + use_crosswalk_user_history: + match_lost_and_appeared_users: true + remember_lost_users: true # parameters for lc prediction lane_change_detection: diff --git a/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp b/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp index e0a9ee51aa30d..b98b257808be2 100644 --- a/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp +++ b/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp @@ -48,6 +48,7 @@ #include <optional> #include <string> #include <unordered_map> +#include <unordered_set> #include <utility> #include <vector> @@ -144,6 +145,7 @@ class MapBasedPredictionNode : public rclcpp::Node std::unordered_map<std::string, std::deque<ObjectData>> objects_history_; std::map<std::pair<std::string, lanelet::Id>, rclcpp::Time> stopped_times_against_green_; std::unordered_map<std::string, std::deque<CrosswalkUserData>> crosswalk_users_history_; + std::unordered_map<std::string, std::string> known_matches_; // Lanelet Map Pointers std::shared_ptr<lanelet::LaneletMap> lanelet_map_ptr_; @@ -207,6 +209,9 @@ class MapBasedPredictionNode : public rclcpp::Node std::vector<double> distance_set_for_no_intention_to_walk_; std::vector<double> timeout_set_for_no_intention_to_walk_; + bool match_lost_and_appeared_crosswalk_users_; + bool remember_lost_crosswalk_users_; + std::unique_ptr<tier4_autoware_utils::PublishedTimePublisher> published_time_publisher_; // Member Functions @@ -244,7 +249,8 @@ class MapBasedPredictionNode : public rclcpp::Node void updateCrosswalkUserHistory( const std_msgs::msg::Header & header, const TrackedObject & object, const std::string & object_id); - + std::string tryMatchNewObjectToDisappeared( + const std::string & object_id, std::unordered_map<std::string, TrackedObject> & current_users); std::vector<PredictedRefPath> getPredictedReferencePath( const TrackedObject & object, const LaneletsData & current_lanelets_data, const double object_detected_time); diff --git a/perception/map_based_prediction/src/map_based_prediction_node.cpp b/perception/map_based_prediction/src/map_based_prediction_node.cpp index fdea487eb1e3f..e8b578537f465 100644 --- a/perception/map_based_prediction/src/map_based_prediction_node.cpp +++ b/perception/map_based_prediction/src/map_based_prediction_node.cpp @@ -822,7 +822,10 @@ MapBasedPredictionNode::MapBasedPredictionNode(const rclcpp::NodeOptions & node_ * parameter control the estimated path length = vx * th * (rate) */ prediction_time_horizon_rate_for_validate_lane_length_ = declare_parameter<double>("prediction_time_horizon_rate_for_validate_shoulder_lane_length"); - + match_lost_and_appeared_crosswalk_users_ = + declare_parameter<bool>("use_crosswalk_user_history.match_lost_and_appeared_users"); + remember_lost_crosswalk_users_ = + declare_parameter<bool>("use_crosswalk_user_history.remember_lost_users"); use_vehicle_acceleration_ = declare_parameter<bool>("use_vehicle_acceleration"); speed_limit_multiplier_ = declare_parameter<double>("speed_limit_multiplier"); acceleration_exponential_half_life_ = @@ -969,6 +972,14 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt auto invalidated_crosswalk_users = removeOldObjectsHistory( objects_detected_time, object_buffer_time_length_, crosswalk_users_history_); + // delete matches that point to invalid object + for (auto it = known_matches_.begin(); it != known_matches_.end();) { + if (invalidated_crosswalk_users.count(it->second)) { + it = known_matches_.erase(it); + } else { + ++it; + } + } // result output PredictedObjects output; @@ -978,6 +989,19 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt // result debug visualization_msgs::msg::MarkerArray debug_markers; + // get current crosswalk users for later prediction + std::unordered_map<std::string, TrackedObject> current_crosswalk_users; + for (const auto & object : in_objects->objects) { + const auto label_for_prediction = + changeLabelForPrediction(object.classification.front().label, object, lanelet_map_ptr_); + if ( + label_for_prediction == ObjectClassification::PEDESTRIAN || + label_for_prediction == ObjectClassification::BICYCLE) { + current_crosswalk_users[tier4_autoware_utils::toHexString(object.object_id)] = object; + } + } + std::unordered_set<std::string> predicted_crosswalk_users_ids; + for (const auto & object : in_objects->objects) { std::string object_id = tier4_autoware_utils::toHexString(object.object_id); TrackedObject transformed_object = object; @@ -998,6 +1022,12 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt switch (label) { case ObjectClassification::PEDESTRIAN: case ObjectClassification::BICYCLE: { + std::string object_id = tier4_autoware_utils::toHexString(object.object_id); + if (match_lost_and_appeared_crosswalk_users_) { + object_id = tryMatchNewObjectToDisappeared(object_id, current_crosswalk_users); + } + predicted_crosswalk_users_ids.insert(object_id); + updateCrosswalkUserHistory(output.header, transformed_object, object_id); const auto predicted_object_crosswalk = getPredictedObjectAsCrosswalkUser(transformed_object); output.objects.push_back(predicted_object_crosswalk); @@ -1163,6 +1193,19 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt } } + // process lost crosswalk users to tackle unstable detection + if (remember_lost_crosswalk_users_) { + for (const auto & [id, crosswalk_user] : crosswalk_users_history_) { + // get a predicted path for crosswalk users in history who didn't get path yet using latest + // message + if (predicted_crosswalk_users_ids.count(id) == 0) { + const auto predicted_object = + getPredictedObjectAsCrosswalkUser(crosswalk_user.back().tracked_object); + output.objects.push_back(predicted_object); + } + } + } + // Publish Results pub_objects_->publish(output); published_time_publisher_->publish_if_subscribed(pub_objects_, output.header.stamp); @@ -1188,6 +1231,51 @@ void MapBasedPredictionNode::updateCrosswalkUserHistory( } } +std::string MapBasedPredictionNode::tryMatchNewObjectToDisappeared( + const std::string & object_id, std::unordered_map<std::string, TrackedObject> & current_users) +{ + if (known_matches_.count(object_id)) { + std::string match_id = known_matches_[object_id]; + // object in the history is already matched to something (possibly itself) + if (crosswalk_users_history_.count(match_id)) { + // avoid matching two appeared users to one user in history + current_users[match_id] = crosswalk_users_history_[match_id].back().tracked_object; + return match_id; + } else { + RCLCPP_WARN_STREAM( + get_logger(), "Crosswalk user was " << object_id << "was matched to " << match_id + << " but the history has deleted. Rematching"); + } + } + std::string match_id = object_id; + double best_score = std::numeric_limits<double>::max(); + auto pos0 = current_users[object_id].kinematics.pose_with_covariance.pose.position; + for (const auto & [user_id, user_history] : crosswalk_users_history_) { + // user present in current_users and will be matched to itself + if (current_users.count(user_id)) { + continue; + } + // TODO(dkoldaev): implement more sophisticated scoring, for now simply dst to last position in + // history + auto pos = user_history.back().tracked_object.kinematics.pose_with_covariance.pose.position; + double score = std::hypot(pos.x - pos0.x, pos.y - pos0.y); + if (score < best_score) { + best_score = score; + match_id = user_id; + } + } + + if (object_id != match_id) { + RCLCPP_INFO_STREAM( + get_logger(), "[Map Based Prediction]: Matched " << object_id << " to " << match_id); + // avoid matching two appeared users to one user in history + current_users[match_id] = crosswalk_users_history_[match_id].back().tracked_object; + } + + known_matches_[object_id] = match_id; + return match_id; +} + bool MapBasedPredictionNode::doesPathCrossAnyFence(const PredictedPath & predicted_path) { const lanelet::ConstLineStrings3d & all_fences = From ff796f934e6cf8f5e2e9e3f302f471c78456451a Mon Sep 17 00:00:00 2001 From: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> Date: Wed, 8 May 2024 10:21:23 +0900 Subject: [PATCH 05/10] renaming and log fixes Signed-off-by: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> --- .../map_based_prediction_node.hpp | 6 +-- .../src/map_based_prediction_node.cpp | 44 ++++++++++--------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp b/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp index b98b257808be2..213f18d63ef3a 100644 --- a/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp +++ b/perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp @@ -142,7 +142,7 @@ class MapBasedPredictionNode : public rclcpp::Node std::unique_ptr<tier4_autoware_utils::DebugPublisher> processing_time_publisher_; // Object History - std::unordered_map<std::string, std::deque<ObjectData>> objects_history_; + std::unordered_map<std::string, std::deque<ObjectData>> road_users_history; std::map<std::pair<std::string, lanelet::Id>, rclcpp::Time> stopped_times_against_green_; std::unordered_map<std::string, std::deque<CrosswalkUserData>> crosswalk_users_history_; std::unordered_map<std::string, std::string> known_matches_; @@ -234,7 +234,7 @@ class MapBasedPredictionNode : public rclcpp::Node PredictedObject getPredictedObjectAsCrosswalkUser(const TrackedObject & object); - void cleanupOldStoppedOnGreenTimes(const TrackedObjects::ConstSharedPtr in_objects); + void removeStaleTrafficLightInfo(const TrackedObjects::ConstSharedPtr in_objects); LaneletsData getCurrentLanelets(const TrackedObject & object); bool checkCloseLaneletCondition( @@ -243,7 +243,7 @@ class MapBasedPredictionNode : public rclcpp::Node const lanelet::Lanelet & current_lanelet, const TrackedObject & object) const; void updateObjectData(TrackedObject & object); - void updateObjectsHistory( + void updateRoadUsersHistory( const std_msgs::msg::Header & header, const TrackedObject & object, const LaneletsData & current_lanelets_data); void updateCrosswalkUserHistory( diff --git a/perception/map_based_prediction/src/map_based_prediction_node.cpp b/perception/map_based_prediction/src/map_based_prediction_node.cpp index e8b578537f465..ebc8cc65a9850 100644 --- a/perception/map_based_prediction/src/map_based_prediction_node.cpp +++ b/perception/map_based_prediction/src/map_based_prediction_node.cpp @@ -967,8 +967,8 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt // Remove old objects information in object history const double objects_detected_time = rclcpp::Time(in_objects->header.stamp).seconds(); - removeOldObjectsHistory(objects_detected_time, object_buffer_time_length_, objects_history_); - cleanupOldStoppedOnGreenTimes(in_objects); + removeOldObjectsHistory(objects_detected_time, object_buffer_time_length_, road_users_history); + removeStaleTrafficLightInfo(in_objects); auto invalidated_crosswalk_users = removeOldObjectsHistory( objects_detected_time, object_buffer_time_length_, crosswalk_users_history_); @@ -997,7 +997,8 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt if ( label_for_prediction == ObjectClassification::PEDESTRIAN || label_for_prediction == ObjectClassification::BICYCLE) { - current_crosswalk_users[tier4_autoware_utils::toHexString(object.object_id)] = object; + const std::string object_id = tier4_autoware_utils::toHexString(object.object_id); + current_crosswalk_users.emplace(object_id, object); } } std::unordered_set<std::string> predicted_crosswalk_users_ids; @@ -1045,7 +1046,7 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt const auto current_lanelets = getCurrentLanelets(transformed_object); // Update Objects History - updateObjectsHistory(output.header, transformed_object, current_lanelets); + updateRoadUsersHistory(output.header, transformed_object, current_lanelets); // For off lane obstacles if (current_lanelets.empty()) { @@ -1243,8 +1244,9 @@ std::string MapBasedPredictionNode::tryMatchNewObjectToDisappeared( return match_id; } else { RCLCPP_WARN_STREAM( - get_logger(), "Crosswalk user was " << object_id << "was matched to " << match_id - << " but the history has deleted. Rematching"); + get_logger(), "Crosswalk user was " + << object_id << "was matched to " << match_id + << " but history for the crosswalk user was deleted. Rematching"); } } std::string match_id = object_id; @@ -1496,7 +1498,7 @@ void MapBasedPredictionNode::updateObjectData(TrackedObject & object) return; } -void MapBasedPredictionNode::cleanupOldStoppedOnGreenTimes( +void MapBasedPredictionNode::removeStaleTrafficLightInfo( const TrackedObjects::ConstSharedPtr in_objects) { for (auto it = stopped_times_against_green_.begin(); it != stopped_times_against_green_.end();) { @@ -1613,9 +1615,9 @@ bool MapBasedPredictionNode::checkCloseLaneletCondition( // If the object is in the objects history, we check if the target lanelet is // inside the current lanelets id or following lanelets const std::string object_id = tier4_autoware_utils::toHexString(object.object_id); - if (objects_history_.count(object_id) != 0) { + if (road_users_history.count(object_id) != 0) { const std::vector<lanelet::ConstLanelet> & possible_lanelet = - objects_history_.at(object_id).back().future_possible_lanelets; + road_users_history.at(object_id).back().future_possible_lanelets; bool not_in_possible_lanelet = std::find(possible_lanelet.begin(), possible_lanelet.end(), lanelet.second) == @@ -1682,7 +1684,7 @@ float MapBasedPredictionNode::calculateLocalLikelihood( return static_cast<float>(1.0 / dist); } -void MapBasedPredictionNode::updateObjectsHistory( +void MapBasedPredictionNode::updateRoadUsersHistory( const std_msgs::msg::Header & header, const TrackedObject & object, const LaneletsData & current_lanelets_data) { @@ -1706,13 +1708,13 @@ void MapBasedPredictionNode::updateObjectsHistory( single_object_data.lateral_kinematics_set[current_lane] = lateral_kinematics; } - if (objects_history_.count(object_id) == 0) { + if (road_users_history.count(object_id) == 0) { // New Object(Create a new object in object histories) std::deque<ObjectData> object_data = {single_object_data}; - objects_history_.emplace(object_id, object_data); + road_users_history.emplace(object_id, object_data); } else { // Object that is already in the object buffer - std::deque<ObjectData> & object_data = objects_history_.at(object_id); + std::deque<ObjectData> & object_data = road_users_history.at(object_id); // get previous object data and update const auto prev_object_data = object_data.back(); updateLateralKinematicsVector( @@ -1900,10 +1902,10 @@ Maneuver MapBasedPredictionNode::predictObjectManeuver( }(); const std::string object_id = tier4_autoware_utils::toHexString(object.object_id); - if (objects_history_.count(object_id) == 0) { + if (road_users_history.count(object_id) == 0) { return current_maneuver; } - auto & object_info = objects_history_.at(object_id); + auto & object_info = road_users_history.at(object_id); // update maneuver in object history if (!object_info.empty()) { @@ -1939,11 +1941,11 @@ Maneuver MapBasedPredictionNode::predictObjectManeuverByTimeToLaneChange( { // Step1. Check if we have the object in the buffer const std::string object_id = tier4_autoware_utils::toHexString(object.object_id); - if (objects_history_.count(object_id) == 0) { + if (road_users_history.count(object_id) == 0) { return Maneuver::LANE_FOLLOW; } - const std::deque<ObjectData> & object_info = objects_history_.at(object_id); + const std::deque<ObjectData> & object_info = road_users_history.at(object_id); // Step2. Check if object history length longer than history_time_length const int latest_id = static_cast<int>(object_info.size()) - 1; @@ -2010,11 +2012,11 @@ Maneuver MapBasedPredictionNode::predictObjectManeuverByLatDiffDistance( { // Step1. Check if we have the object in the buffer const std::string object_id = tier4_autoware_utils::toHexString(object.object_id); - if (objects_history_.count(object_id) == 0) { + if (road_users_history.count(object_id) == 0) { return Maneuver::LANE_FOLLOW; } - const std::deque<ObjectData> & object_info = objects_history_.at(object_id); + const std::deque<ObjectData> & object_info = road_users_history.at(object_id); const double current_time = (this->get_clock()->now()).seconds(); // Step2. Get the previous id @@ -2171,12 +2173,12 @@ void MapBasedPredictionNode::updateFuturePossibleLanelets( const TrackedObject & object, const lanelet::routing::LaneletPaths & paths) { std::string object_id = tier4_autoware_utils::toHexString(object.object_id); - if (objects_history_.count(object_id) == 0) { + if (road_users_history.count(object_id) == 0) { return; } std::vector<lanelet::ConstLanelet> & possible_lanelets = - objects_history_.at(object_id).back().future_possible_lanelets; + road_users_history.at(object_id).back().future_possible_lanelets; for (const auto & path : paths) { for (const auto & lanelet : path) { bool not_in_buffer = std::find(possible_lanelets.begin(), possible_lanelets.end(), lanelet) == From 9cc4902deacb0ed7184409a9328a231d21e9b097 Mon Sep 17 00:00:00 2001 From: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> Date: Wed, 8 May 2024 10:29:13 +0900 Subject: [PATCH 06/10] const for non changing objects Signed-off-by: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> --- .../src/map_based_prediction_node.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/perception/map_based_prediction/src/map_based_prediction_node.cpp b/perception/map_based_prediction/src/map_based_prediction_node.cpp index ebc8cc65a9850..23991afe44445 100644 --- a/perception/map_based_prediction/src/map_based_prediction_node.cpp +++ b/perception/map_based_prediction/src/map_based_prediction_node.cpp @@ -1251,7 +1251,7 @@ std::string MapBasedPredictionNode::tryMatchNewObjectToDisappeared( } std::string match_id = object_id; double best_score = std::numeric_limits<double>::max(); - auto pos0 = current_users[object_id].kinematics.pose_with_covariance.pose.position; + const auto object_pos = current_users[object_id].kinematics.pose_with_covariance.pose.position; for (const auto & [user_id, user_history] : crosswalk_users_history_) { // user present in current_users and will be matched to itself if (current_users.count(user_id)) { @@ -1259,8 +1259,10 @@ std::string MapBasedPredictionNode::tryMatchNewObjectToDisappeared( } // TODO(dkoldaev): implement more sophisticated scoring, for now simply dst to last position in // history - auto pos = user_history.back().tracked_object.kinematics.pose_with_covariance.pose.position; - double score = std::hypot(pos.x - pos0.x, pos.y - pos0.y); + const auto match_candidate_pos = + user_history.back().tracked_object.kinematics.pose_with_covariance.pose.position; + const double score = + std::hypot(match_candidate_pos.x - object_pos.x, match_candidate_pos.y - object_pos.y); if (score < best_score) { best_score = score; match_id = user_id; From 2debdd6ce462dfdc8b7d4a210a5a7c9bf83da198 Mon Sep 17 00:00:00 2001 From: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> Date: Wed, 8 May 2024 10:32:26 +0900 Subject: [PATCH 07/10] disable history by default Signed-off-by: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> --- .../config/map_based_prediction.param.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/perception/map_based_prediction/config/map_based_prediction.param.yaml b/perception/map_based_prediction/config/map_based_prediction.param.yaml index c825e2c3776da..a1b776bdb6393 100644 --- a/perception/map_based_prediction/config/map_based_prediction.param.yaml +++ b/perception/map_based_prediction/config/map_based_prediction.param.yaml @@ -28,8 +28,8 @@ # parameter for shoulder lane prediction prediction_time_horizon_rate_for_validate_shoulder_lane_length: 0.8 use_crosswalk_user_history: - match_lost_and_appeared_users: true - remember_lost_users: true + match_lost_and_appeared_users: false + remember_lost_users: false # parameters for lc prediction lane_change_detection: From cc9f2fe1600d221dd50c451b64b4be9d8c995bb4 Mon Sep 17 00:00:00 2001 From: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> Date: Wed, 8 May 2024 10:46:51 +0900 Subject: [PATCH 08/10] use RAII to improve early return readability in tryMatch... function Signed-off-by: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> --- .../src/map_based_prediction_node.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/perception/map_based_prediction/src/map_based_prediction_node.cpp b/perception/map_based_prediction/src/map_based_prediction_node.cpp index 23991afe44445..88530a1c989a2 100644 --- a/perception/map_based_prediction/src/map_based_prediction_node.cpp +++ b/perception/map_based_prediction/src/map_based_prediction_node.cpp @@ -1235,7 +1235,11 @@ void MapBasedPredictionNode::updateCrosswalkUserHistory( std::string MapBasedPredictionNode::tryMatchNewObjectToDisappeared( const std::string & object_id, std::unordered_map<std::string, TrackedObject> & current_users) { - if (known_matches_.count(object_id)) { + const auto known_match_opt = [&]() -> std::optional<std::string> { + if (!known_matches_.count(object_id)) { + return std::nullopt; + } + std::string match_id = known_matches_[object_id]; // object in the history is already matched to something (possibly itself) if (crosswalk_users_history_.count(match_id)) { @@ -1248,7 +1252,13 @@ std::string MapBasedPredictionNode::tryMatchNewObjectToDisappeared( << object_id << "was matched to " << match_id << " but history for the crosswalk user was deleted. Rematching"); } + return std::nullopt; + }(); + // early return if the match is already known + if (known_match_opt.has_value()) { + return known_match_opt.value(); } + std::string match_id = object_id; double best_score = std::numeric_limits<double>::max(); const auto object_pos = current_users[object_id].kinematics.pose_with_covariance.pose.position; From 52b49e3bb48f5cf63713e3add76d326acd2f20ce Mon Sep 17 00:00:00 2001 From: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> Date: Wed, 8 May 2024 10:49:55 +0900 Subject: [PATCH 09/10] less conditionals in update crosswalk history Signed-off-by: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> --- .../map_based_prediction/src/map_based_prediction_node.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/perception/map_based_prediction/src/map_based_prediction_node.cpp b/perception/map_based_prediction/src/map_based_prediction_node.cpp index 88530a1c989a2..dbc117fbdbe3c 100644 --- a/perception/map_based_prediction/src/map_based_prediction_node.cpp +++ b/perception/map_based_prediction/src/map_based_prediction_node.cpp @@ -1225,11 +1225,13 @@ void MapBasedPredictionNode::updateCrosswalkUserHistory( CrosswalkUserData crosswalk_user_data; crosswalk_user_data.header = header; crosswalk_user_data.tracked_object = object; + if (crosswalk_users_history_.count(object_id) == 0) { crosswalk_users_history_.emplace(object_id, std::deque<CrosswalkUserData>{crosswalk_user_data}); - } else { - crosswalk_users_history_.at(object_id).push_back(crosswalk_user_data); + return; } + + crosswalk_users_history_.at(object_id).push_back(crosswalk_user_data); } std::string MapBasedPredictionNode::tryMatchNewObjectToDisappeared( From 6826892fc8ac44116ea24ac42a0fa14f8065133f Mon Sep 17 00:00:00 2001 From: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> Date: Wed, 8 May 2024 14:44:35 +0900 Subject: [PATCH 10/10] improve readability in removing stale object data Signed-off-by: Dmitrii Koldaev <dmitrii.koldaev@tier4.jp> --- .../map_based_prediction/src/map_based_prediction_node.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/perception/map_based_prediction/src/map_based_prediction_node.cpp b/perception/map_based_prediction/src/map_based_prediction_node.cpp index dbc117fbdbe3c..3942af905ea22 100644 --- a/perception/map_based_prediction/src/map_based_prediction_node.cpp +++ b/perception/map_based_prediction/src/map_based_prediction_node.cpp @@ -612,12 +612,10 @@ std::unordered_set<std::string> removeOldObjectsHistory( // Delete old information while (!object_data.empty()) { const double post_object_time = rclcpp::Time(object_data.front().header.stamp).seconds(); - if (current_time - post_object_time > buffer_time) { - // Delete Old Position - object_data.pop_front(); - } else { + if (current_time - post_object_time <= buffer_time) { break; } + object_data.pop_front(); } if (object_data.empty()) {