|
34 | 34 | #include <algorithm>
|
35 | 35 | #include <chrono>
|
36 | 36 | #include <cmath>
|
| 37 | +#include <functional> |
37 | 38 | #include <limits>
|
38 | 39 |
|
39 | 40 | namespace map_based_prediction
|
@@ -207,6 +208,114 @@ double calcAbsYawDiffBetweenLaneletAndObject(
|
207 | 208 | return abs_norm_delta;
|
208 | 209 | }
|
209 | 210 |
|
| 211 | +/** |
| 212 | + * @brief Get the Right LineSharing Lanelets object |
| 213 | + * |
| 214 | + * @param current_lanelet |
| 215 | + * @param lanelet_map_ptr |
| 216 | + * @return lanelet::ConstLanelets |
| 217 | + */ |
| 218 | +lanelet::ConstLanelets getRightLineSharingLanelets( |
| 219 | + const lanelet::ConstLanelet & current_lanelet, const lanelet::LaneletMapPtr & lanelet_map_ptr) |
| 220 | +{ |
| 221 | + lanelet::ConstLanelets |
| 222 | + output_lanelets; // create an empty container of type lanelet::ConstLanelets |
| 223 | + |
| 224 | + // step1: look for lane sharing current right bound |
| 225 | + lanelet::Lanelets right_lane_candidates = |
| 226 | + lanelet_map_ptr->laneletLayer.findUsages(current_lanelet.rightBound()); |
| 227 | + for (auto & candidate : right_lane_candidates) { |
| 228 | + // exclude self lanelet |
| 229 | + if (candidate == current_lanelet) continue; |
| 230 | + // if candidate has linestring as leftbound, assign it to output |
| 231 | + if (candidate.leftBound() == current_lanelet.rightBound()) { |
| 232 | + output_lanelets.push_back(candidate); |
| 233 | + } |
| 234 | + } |
| 235 | + return output_lanelets; // return empty |
| 236 | +} |
| 237 | + |
| 238 | +/** |
| 239 | + * @brief Get the Left LineSharing Lanelets object |
| 240 | + * |
| 241 | + * @param current_lanelet |
| 242 | + * @param lanelet_map_ptr |
| 243 | + * @return lanelet::ConstLanelets |
| 244 | + */ |
| 245 | +lanelet::ConstLanelets getLeftLineSharingLanelets( |
| 246 | + const lanelet::ConstLanelet & current_lanelet, const lanelet::LaneletMapPtr & lanelet_map_ptr) |
| 247 | +{ |
| 248 | + lanelet::ConstLanelets |
| 249 | + output_lanelets; // create an empty container of type lanelet::ConstLanelets |
| 250 | + |
| 251 | + // step1: look for lane sharing current left bound |
| 252 | + lanelet::Lanelets left_lane_candidates = |
| 253 | + lanelet_map_ptr->laneletLayer.findUsages(current_lanelet.leftBound()); |
| 254 | + for (auto & candidate : left_lane_candidates) { |
| 255 | + // exclude self lanelet |
| 256 | + if (candidate == current_lanelet) continue; |
| 257 | + // if candidate has linestring as rightbound, assign it to output |
| 258 | + if (candidate.rightBound() == current_lanelet.leftBound()) { |
| 259 | + output_lanelets.push_back(candidate); |
| 260 | + } |
| 261 | + } |
| 262 | + return output_lanelets; // return empty |
| 263 | +} |
| 264 | + |
| 265 | +/** |
| 266 | + * @brief Check if the lanelet is isolated in routing graph |
| 267 | + * @param current_lanelet |
| 268 | + * @param lanelet_map_ptr |
| 269 | + */ |
| 270 | +bool isIsolatedLanelet( |
| 271 | + const lanelet::ConstLanelet & lanelet, lanelet::routing::RoutingGraphPtr & graph) |
| 272 | +{ |
| 273 | + const auto & following_lanelets = graph->following(lanelet); |
| 274 | + const auto & left_lanelets = graph->lefts(lanelet); |
| 275 | + const auto & right_lanelets = graph->rights(lanelet); |
| 276 | + return left_lanelets.empty() && right_lanelets.empty() && following_lanelets.empty(); |
| 277 | +} |
| 278 | + |
| 279 | +/** |
| 280 | + * @brief Get the Possible Paths For Isolated Lanelet object |
| 281 | + * @param lanelet |
| 282 | + * @return lanelet::routing::LaneletPaths |
| 283 | + */ |
| 284 | +lanelet::routing::LaneletPaths getPossiblePathsForIsolatedLanelet( |
| 285 | + const lanelet::ConstLanelet & lanelet) |
| 286 | +{ |
| 287 | + lanelet::ConstLanelets possible_lanelets; |
| 288 | + possible_lanelets.push_back(lanelet); |
| 289 | + lanelet::routing::LaneletPaths possible_paths; |
| 290 | + // need to init path with constlanelets |
| 291 | + lanelet::routing::LaneletPath possible_path(possible_lanelets); |
| 292 | + possible_paths.push_back(possible_path); |
| 293 | + return possible_paths; |
| 294 | +} |
| 295 | + |
| 296 | +/** |
| 297 | + * @brief validate isolated lanelet length has enough length for prediction |
| 298 | + * @param lanelet |
| 299 | + * @param object: object information for calc length threshold |
| 300 | + * @param prediction_time: time horizon[s] for calc length threshold |
| 301 | + * @return bool |
| 302 | + */ |
| 303 | +bool validateIsolatedLaneletLength( |
| 304 | + const lanelet::ConstLanelet & lanelet, const TrackedObject & object, const double prediction_time) |
| 305 | +{ |
| 306 | + // get closest center line point to object |
| 307 | + const auto & center_line = lanelet.centerline2d(); |
| 308 | + const auto & obj_pos = object.kinematics.pose_with_covariance.pose.position; |
| 309 | + const lanelet::BasicPoint2d obj_point(obj_pos.x, obj_pos.y); |
| 310 | + // get end point of the center line |
| 311 | + const auto & end_point = center_line.back(); |
| 312 | + // calc approx distance between closest point and end point |
| 313 | + const double approx_distance = lanelet::geometry::distance2d(obj_point, end_point); |
| 314 | + const double min_length = |
| 315 | + object.kinematics.twist_with_covariance.twist.linear.x * prediction_time; |
| 316 | + return approx_distance > min_length; |
| 317 | +} |
| 318 | + |
210 | 319 | lanelet::ConstLanelets getLanelets(const map_based_prediction::LaneletsData & data)
|
211 | 320 | {
|
212 | 321 | lanelet::ConstLanelets lanelets;
|
@@ -522,6 +631,10 @@ MapBasedPredictionNode::MapBasedPredictionNode(const rclcpp::NodeOptions & node_
|
522 | 631 | declare_parameter<int>("lane_change_detection.num_continuous_state_transition");
|
523 | 632 | }
|
524 | 633 | reference_path_resolution_ = declare_parameter("reference_path_resolution", 0.5);
|
| 634 | + /* prediction path will disabled when the estimated path length exceeds lanelet length. This |
| 635 | + * parameter control the estimated path length = vx * th * (rate) */ |
| 636 | + prediction_time_horizon_rate_for_validate_lane_length_ = |
| 637 | + declare_parameter("prediction_time_horizon_rate_for_validate_lane_length", 0.8); |
525 | 638 |
|
526 | 639 | path_generator_ = std::make_shared<PathGenerator>(
|
527 | 640 | prediction_time_horizon_, prediction_sampling_time_interval_, min_crosswalk_user_velocity_);
|
@@ -1119,25 +1232,69 @@ std::vector<PredictedRefPath> MapBasedPredictionNode::getPredictedReferencePath(
|
1119 | 1232 | const double search_dist = prediction_time_horizon_ * obj_vel +
|
1120 | 1233 | lanelet::utils::getLaneletLength3d(current_lanelet_data.lanelet);
|
1121 | 1234 | lanelet::routing::PossiblePathsParams possible_params{search_dist, {}, 0, false, true};
|
| 1235 | + const double validate_time_horizon = |
| 1236 | + prediction_time_horizon_ * prediction_time_horizon_rate_for_validate_lane_length_; |
| 1237 | + |
| 1238 | + // lambda function to get possible paths for isolated lanelet |
| 1239 | + // isolated is often caused by lanelet with no connection e.g. shoulder-lane |
| 1240 | + auto getPathsForNormalOrIsolatedLanelet = [&](const lanelet::ConstLanelet & lanelet) { |
| 1241 | + // if lanelet is not isolated, return normal possible paths |
| 1242 | + if (!isIsolatedLanelet(lanelet, routing_graph_ptr_)) { |
| 1243 | + return routing_graph_ptr_->possiblePaths(lanelet, possible_params); |
| 1244 | + } |
| 1245 | + // if lanelet is isolated, check if it has enough length |
| 1246 | + if (!validateIsolatedLaneletLength(lanelet, object, validate_time_horizon)) { |
| 1247 | + return lanelet::routing::LaneletPaths{}; |
| 1248 | + } else { |
| 1249 | + // if lanelet has enough length, return possible paths |
| 1250 | + return getPossiblePathsForIsolatedLanelet(lanelet); |
| 1251 | + } |
| 1252 | + }; |
| 1253 | + |
| 1254 | + // lambda function to extract left/right lanelets |
| 1255 | + auto getLeftOrRightLanelets = [&]( |
| 1256 | + const lanelet::ConstLanelet & lanelet, |
| 1257 | + const bool get_left) -> std::optional<lanelet::ConstLanelet> { |
| 1258 | + const auto opt = |
| 1259 | + get_left ? routing_graph_ptr_->left(lanelet) : routing_graph_ptr_->right(lanelet); |
| 1260 | + if (!!opt) { |
| 1261 | + return *opt; |
| 1262 | + } |
| 1263 | + const auto adjacent = get_left ? routing_graph_ptr_->adjacentLeft(lanelet) |
| 1264 | + : routing_graph_ptr_->adjacentRight(lanelet); |
| 1265 | + if (!!adjacent) { |
| 1266 | + return *adjacent; |
| 1267 | + } |
| 1268 | + // search for unconnected lanelet |
| 1269 | + const auto unconnected_lanelets = get_left |
| 1270 | + ? getLeftLineSharingLanelets(lanelet, lanelet_map_ptr_) |
| 1271 | + : getRightLineSharingLanelets(lanelet, lanelet_map_ptr_); |
| 1272 | + // just return first candidate of unconnected lanelet for now |
| 1273 | + if (!unconnected_lanelets.empty()) { |
| 1274 | + return unconnected_lanelets.front(); |
| 1275 | + } |
| 1276 | + // if no candidate lanelet found, return empty |
| 1277 | + return std::nullopt; |
| 1278 | + }; |
1122 | 1279 |
|
1123 | 1280 | // Step1. Get the path
|
1124 | 1281 | // Step1.1 Get the left lanelet
|
1125 | 1282 | lanelet::routing::LaneletPaths left_paths;
|
1126 |
| - auto opt_left = routing_graph_ptr_->left(current_lanelet_data.lanelet); |
1127 |
| - if (!!opt_left) { |
1128 |
| - left_paths = routing_graph_ptr_->possiblePaths(*opt_left, possible_params); |
| 1283 | + const auto left_lanelet = getLeftOrRightLanelets(current_lanelet_data.lanelet, true); |
| 1284 | + if (!!left_lanelet) { |
| 1285 | + left_paths = getPathsForNormalOrIsolatedLanelet(left_lanelet.value()); |
1129 | 1286 | }
|
1130 | 1287 |
|
1131 | 1288 | // Step1.2 Get the right lanelet
|
1132 | 1289 | lanelet::routing::LaneletPaths right_paths;
|
1133 |
| - auto opt_right = routing_graph_ptr_->right(current_lanelet_data.lanelet); |
1134 |
| - if (!!opt_right) { |
1135 |
| - right_paths = routing_graph_ptr_->possiblePaths(*opt_right, possible_params); |
| 1290 | + const auto right_lanelet = getLeftOrRightLanelets(current_lanelet_data.lanelet, false); |
| 1291 | + if (!!right_lanelet) { |
| 1292 | + right_paths = getPathsForNormalOrIsolatedLanelet(right_lanelet.value()); |
1136 | 1293 | }
|
1137 | 1294 |
|
1138 | 1295 | // Step1.3 Get the centerline
|
1139 | 1296 | lanelet::routing::LaneletPaths center_paths =
|
1140 |
| - routing_graph_ptr_->possiblePaths(current_lanelet_data.lanelet, possible_params); |
| 1297 | + getPathsForNormalOrIsolatedLanelet(current_lanelet_data.lanelet); |
1141 | 1298 |
|
1142 | 1299 | // Skip calculations if all paths are empty
|
1143 | 1300 | if (left_paths.empty() && right_paths.empty() && center_paths.empty()) {
|
|
0 commit comments