qp_frenet_frame.cc 17.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/******************************************************************************
 * Copyright 2017 The Apollo Authors. 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.
 *****************************************************************************/

/**
Z
Zhang Liangliang 已提交
18
 * @file qp_frenet_frame.cc
19
 **/
D
Dong Li 已提交
20
#include "modules/planning/tasks/qp_spline_path/qp_frenet_frame.h"
D
Dong Li 已提交
21

22 23
#include <algorithm>
#include <limits>
D
Dong Li 已提交
24

Z
Zhang Liangliang 已提交
25 26 27
#include "modules/common/proto/pnc_point.pb.h"
#include "modules/planning/proto/planning.pb.h"

28
#include "modules/common/configs/vehicle_config_helper.h"
D
Dong Li 已提交
29 30
#include "modules/common/macro.h"
#include "modules/common/util/util.h"
31
#include "modules/planning/common/planning_gflags.h"
32
#include "modules/planning/common/planning_util.h"
D
Dong Li 已提交
33
#include "modules/planning/math/double.h"
34 35 36 37

namespace apollo {
namespace planning {

38
using common::SpeedPoint;
39
using ConstPathObstacleList = std::vector<const PathObstacle*>;
40

41 42
namespace {

A
Aaron Xiao 已提交
43
constexpr double kEpsilontol = 1e-6;
44
}
A
Aaron Xiao 已提交
45

46
QpFrenetFrame::QpFrenetFrame(const ReferenceLine& reference_line,
D
Dong Li 已提交
47
                             const ConstPathObstacleList& path_obstacles,
48 49 50 51 52
                             const SpeedData& speed_data,
                             const common::FrenetFramePoint& init_frenet_point,
                             const double start_s, const double end_s,
                             const double time_resolution)
    : reference_line_(reference_line),
D
Dong Li 已提交
53
      path_obstacles_(path_obstacles),
54 55 56 57
      speed_data_(speed_data),
      vehicle_param_(
          common::VehicleConfigHelper::instance()->GetConfig().vehicle_param()),
      init_frenet_point_(init_frenet_point),
58
      feasible_longitudinal_upper_bound_(reference_line_.map_path().length()),
59 60 61 62 63
      start_s_(start_s),
      end_s_(end_s),
      time_resolution_(time_resolution) {}

bool QpFrenetFrame::Init(const uint32_t num_points) {
64
  if (num_points < 2) {
65 66
    AERROR << "Number of s points [" << num_points
           << "] is too small to evaluate.";
D
Dong Li 已提交
67 68
    return false;
  }
69

70 71
  constexpr double kMinDistance = 1.0e-8;
  if (std::fabs(start_s_ - end_s_) < kMinDistance) {
72
    AERROR << "Not enough s distance. start_s: " << start_s_
73
           << ", end_s: " << end_s_ << ", kMinDistance: " << kMinDistance;
D
Dong Li 已提交
74 75
    return false;
  }
76

77
  if (!CalculateDiscretizedVehicleLocation()) {
D
Dong Li 已提交
78 79 80
    AERROR << "Fail to calculate discretized vehicle location!";
    return false;
  }
81

82
  const auto inf = std::numeric_limits<double>::infinity();
83
  const double resolution = (end_s_ - start_s_) / num_points;
84
  double s = start_s_;
85
  while (s <= end_s_) {
86
    evaluated_knots_.push_back(s);
87 88 89
    hdmap_bound_.emplace_back(-inf, inf);
    static_obstacle_bound_.emplace_back(-inf, inf);
    dynamic_obstacle_bound_.emplace_back(-inf, inf);
90
    s += resolution;
91 92 93
  }

  // initialize calculation here
94 95
  CalculateHDMapBound();

96 97
  if (!CalculateObstacleBound()) {
    AERROR << "Calculate obstacle bound failed!";
D
Dong Li 已提交
98 99 100
    return false;
  }
  return true;
101 102
}

103 104
const ReferenceLine& QpFrenetFrame::GetReferenceLine() const {
  return reference_line_;
105 106 107
}

double QpFrenetFrame::feasible_longitudinal_upper_bound() const {
108
  return feasible_longitudinal_upper_bound_;
109 110
}

111 112
bool QpFrenetFrame::GetMapBound(const double s,
                                std::pair<double, double>* const bound) const {
113
  return GetBound(s, hdmap_bound_, bound);
114 115
}

116
bool QpFrenetFrame::GetStaticObstacleBound(
117
    const double s, std::pair<double, double>* const bound) const {
118
  return GetBound(s, static_obstacle_bound_, bound);
119 120
}

121
bool QpFrenetFrame::GetDynamicObstacleBound(
122
    const double s, std::pair<double, double>* const bound) const {
123
  return GetBound(s, dynamic_obstacle_bound_, bound);
124 125
}

126
bool QpFrenetFrame::CalculateDiscretizedVehicleLocation() {
127 128
  double relative_time = 0.0;
  while (relative_time < speed_data_.TotalTime()) {
129
    SpeedPoint veh_point;
130
    if (!speed_data_.EvaluateByTime(relative_time, &veh_point)) {
D
Dong Li 已提交
131 132 133
      AERROR << "Fail to get speed point at relative time " << relative_time;
      return false;
    }
134
    veh_point.set_t(relative_time);
135
    discretized_vehicle_location_.push_back(std::move(veh_point));
136
    relative_time += time_resolution_;
137 138 139 140
  }
  return true;
}

D
Dong Li 已提交
141 142
bool QpFrenetFrame::MapDynamicObstacleWithDecision(
    const PathObstacle& path_obstacle) {
143
  const Obstacle* ptr_obstacle = path_obstacle.Obstacle();
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
  if (!path_obstacle.HasLateralDecision()) {
    AERROR << "object has no lateral decision";
    return false;
  }
  const auto& decision = path_obstacle.LateralDecision();
  if (!decision.has_nudge()) {
    AWARN << "only support nudge now";
    return true;
  }
  const auto& nudge = decision.nudge();
  double buffer = std::fabs(nudge.distance_l());

  int nudge_side = (nudge.type() == ObjectNudge::RIGHT_NUDGE) ? 1 : -1;

  for (const SpeedPoint& veh_point : discretized_vehicle_location_) {
    double time = veh_point.t();
    common::TrajectoryPoint trajectory_point =
        ptr_obstacle->GetPointAtTime(time);
    common::math::Box2d obs_box =
        ptr_obstacle->GetBoundingBox(trajectory_point);
    // project obs_box on reference line
    std::vector<common::math::Vec2d> corners;
    obs_box.GetAllCorners(&corners);
    std::vector<common::SLPoint> sl_corners;

169
    for (const auto& corner_xy : corners) {
170
      common::SLPoint cur_point;
171 172
      if (!reference_line_.xy_to_sl(corner_xy, &cur_point)) {
        AERROR << "Fail to map xy point " << corner_xy.DebugString() << " to "
173 174 175 176 177 178
               << cur_point.ShortDebugString();
        return false;
      }
      // shift box base on buffer
      cur_point.set_l(cur_point.l() - buffer * nudge_side);
      sl_corners.push_back(std::move(cur_point));
179
    }
180 181 182 183 184 185

    for (uint32_t i = 0; i < sl_corners.size(); ++i) {
      common::SLPoint sl_first = sl_corners[i % sl_corners.size()];
      common::SLPoint sl_second = sl_corners[(i + 1) % sl_corners.size()];
      if (sl_first.s() < sl_second.s()) {
        std::swap(sl_first, sl_second);
186 187
      }

188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
      std::pair<double, double> bound = MapLateralConstraint(
          sl_first, sl_second, nudge_side,
          veh_point.s() - vehicle_param_.back_edge_to_center(),
          veh_point.s() + vehicle_param_.front_edge_to_center());

      // update bound map
      double s_resolution = std::fabs(veh_point.v() * time_resolution_);
      double updated_start_s =
          init_frenet_point_.s() + veh_point.s() - s_resolution;
      double updated_end_s =
          init_frenet_point_.s() + veh_point.s() + s_resolution;
      if (updated_end_s > evaluated_knots_.back() ||
          updated_start_s < evaluated_knots_.front()) {
        continue;
      }
      std::pair<uint32_t, uint32_t> update_index_range =
          FindInterval(updated_start_s, updated_end_s);

      for (uint32_t j = update_index_range.first; j < update_index_range.second;
           ++j) {
        dynamic_obstacle_bound_[j].first =
            std::max(bound.first, dynamic_obstacle_bound_[j].first);
        dynamic_obstacle_bound_[j].second =
            std::min(bound.second, dynamic_obstacle_bound_[j].second);
212 213 214 215 216 217
      }
    }
  }
  return true;
}

D
Dong Li 已提交
218 219
bool QpFrenetFrame::MapStaticObstacleWithDecision(
    const PathObstacle& path_obstacle) {
Y
Yajia Zhang 已提交
220
  const auto ptr_obstacle = path_obstacle.Obstacle();
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
  if (!path_obstacle.HasLateralDecision()) {
    AERROR << "obstacle has no lateral decision";
    return false;
  }
  const auto& decision = path_obstacle.LateralDecision();
  if (!decision.has_nudge()) {
    AWARN << "only support nudge decision now";
    return true;
  }
  const auto& nudge = decision.nudge();
  const double buffer = std::fabs(nudge.distance_l());
  if (nudge.type() == ObjectNudge::RIGHT_NUDGE) {
    const auto& box = ptr_obstacle->PerceptionBoundingBox();
    std::vector<common::math::Vec2d> corners;
    box.GetAllCorners(&corners);
    if (!MapPolygon(corners, buffer, -1, &static_obstacle_bound_)) {
      AERROR << "fail to map polygon with id " << path_obstacle.Id()
             << " in qp frenet frame";
      return false;
240
    }
241 242 243 244 245 246 247 248
  } else {
    const auto& box = ptr_obstacle->PerceptionBoundingBox();
    std::vector<common::math::Vec2d> corners;
    box.GetAllCorners(&corners);
    if (!MapPolygon(corners, buffer, 1, &static_obstacle_bound_)) {
      AERROR << "fail to map polygon with id " << path_obstacle.Id()
             << "in qp frenet frame";
      return false;
249 250 251 252 253
    }
  }
  return true;
}

254
bool QpFrenetFrame::MapPolygon(
255
    const std::vector<common::math::Vec2d>& corners, const double buffer,
Y
Yajia Zhang 已提交
256
    const int nudge_side,
257
    std::vector<std::pair<double, double>>* const bound_map) {
D
Dong Li 已提交
258
  std::vector<common::SLPoint> sl_corners;
259

260
  for (const auto& corner_xy : corners) {
D
Dong Li 已提交
261
    common::SLPoint cur_point;
262 263
    if (!reference_line_.xy_to_sl(corner_xy, &cur_point)) {
      AERROR << "Fail to map xy point " << corner_xy.DebugString() << " to "
D
Dong Li 已提交
264 265 266
             << cur_point.DebugString();
      return false;
    }
267
    // shift box base on buffer
268
    cur_point.set_l(cur_point.l() + buffer * nudge_side);
269 270 271
    sl_corners.push_back(std::move(cur_point));
  }

272
  for (uint32_t i = 0; i < sl_corners.size(); ++i) {
273 274 275 276
    if (!MapLine(sl_corners[i % sl_corners.size()],
                 sl_corners[(i + 1) % sl_corners.size()], nudge_side,
                 bound_map)) {
      AERROR << "Map box line (sl) " << sl_corners[i].DebugString() << "->"
D
Dong Li 已提交
277 278 279
             << sl_corners[i + 1].DebugString();
      return false;
    }
280
  }
D
Dong Li 已提交
281
  return true;
282 283
}

284
bool QpFrenetFrame::MapLine(
D
Dong Li 已提交
285 286
    const common::SLPoint& start, const common::SLPoint& end,
    const int nudge_side,
287
    std::vector<std::pair<double, double>>* const constraint) {
D
Dong Li 已提交
288 289
  common::SLPoint near_point = (start.s() < end.s() ? start : end);
  common::SLPoint further_point = (start.s() < end.s() ? end : start);
290
  std::pair<uint32_t, uint32_t> impact_index =
291
      FindInterval(near_point.s(), further_point.s());
292

293 294 295 296
  if ((near_point.s() < start_s_ - vehicle_param_.back_edge_to_center() &&
       further_point.s() < start_s_ - vehicle_param_.back_edge_to_center()) ||
      (near_point.s() > end_s_ + vehicle_param_.front_edge_to_center() &&
       further_point.s() > end_s_ + vehicle_param_.front_edge_to_center())) {
D
Dong Li 已提交
297
    return true;
298 299 300 301 302
  }

  double distance =
      std::max(std::abs(near_point.s() - further_point.s()), 1e-8);

303
  for (uint32_t i = impact_index.first; i <= impact_index.second; ++i) {
304
    double weight = std::abs((evaluated_knots_[i] - near_point.s())) / distance;
305 306 307 308 309 310
    weight = std::max(weight, 0.0);
    weight = std::min(weight, 1.0);
    double boundary =
        near_point.l() * (1 - weight) + further_point.l() * weight;

    if (nudge_side < 0) {
311
      boundary += vehicle_param_.width() / 2;
312 313
      (*constraint)[i].first = std::max(boundary, (*constraint)[i].first);
    } else if (nudge_side > 0) {
314
      boundary -= vehicle_param_.width() / 2;
315 316 317 318 319
      (*constraint)[i].second = std::min(boundary, (*constraint)[i].second);
    }

    if ((*constraint)[i].second < (*constraint)[i].first + 0.3) {
      if (i > 0) {
320 321 322
        feasible_longitudinal_upper_bound_ =
            std::min(evaluated_knots_[i - 1] - kEpsilontol,
                     feasible_longitudinal_upper_bound_);
323
      } else {
324
        feasible_longitudinal_upper_bound_ = start_s_;
D
Dong Li 已提交
325
        return true;
326 327
      }

D
Dong Li 已提交
328 329 330 331 332
      AERROR << "current mapping constraint, sl point impact index "
             << "near_point: " << near_point.DebugString()
             << "further_point: " << further_point.DebugString()
             << "impact_index: " << impact_index << "(*constraint)[" << i << "]"
             << (*constraint)[i];
333 334 335
    }
  }

D
Dong Li 已提交
336
  return true;
337 338
}

339
std::pair<double, double> QpFrenetFrame::MapLateralConstraint(
D
Dong Li 已提交
340 341
    const common::SLPoint& start, const common::SLPoint& end,
    const int nudge_side, const double s_start, const double s_end) {
342 343 344 345 346
  double inf = std::numeric_limits<double>::infinity();
  std::pair<double, double> result = std::make_pair(-inf, inf);

  if (start.s() > s_end || end.s() < s_start) {
    return result;
D
Dong Li 已提交
347 348 349
  }
  double s_front = std::max(start.s(), s_start);
  double s_back = std::min(end.s(), s_end);
350

D
Dong Li 已提交
351 352
  double weight_back = 0.0;
  double weight_front = 0.0;
353

354
  if (Double::Compare((end.s() - start.s()), 0.0) > 0) {
D
Dong Li 已提交
355 356 357
    weight_back = (s_back - end.s()) / (end.s() - start.s());
    weight_front = (s_front - start.s()) / (end.s() - start.s());
  }
358

D
Dong Li 已提交
359 360
  common::SLPoint front = util::interpolate(start, end, weight_front);
  common::SLPoint back = util::interpolate(start, end, weight_back);
361

D
Dong Li 已提交
362 363 364 365 366 367
  if (nudge_side > 0) {
    double l = std::min(front.l(), back.l());
    result.second = l;
  } else if (nudge_side < 0) {
    double l = std::max(front.l(), back.l());
    result.first = l;
368
  }
D
Dong Li 已提交
369
  return result;
370 371
}

372
std::pair<uint32_t, uint32_t> QpFrenetFrame::FindInterval(
373
    const double start, const double end) const {
374 375 376 377
  double new_start = std::max(start - vehicle_param_.front_edge_to_center(),
                              evaluated_knots_.front());
  double new_end = std::min(end + vehicle_param_.back_edge_to_center(),
                            evaluated_knots_.back());
378 379
  uint32_t start_index = FindIndex(new_start);
  uint32_t end_index = FindIndex(new_end);
380

381 382
  if (end > evaluated_knots_[end_index] &&
      end_index + 1 != evaluated_knots_.size()) {
383 384 385 386 387 388
    end_index++;
  }

  return std::make_pair(start_index, end_index);
}

389
void QpFrenetFrame::CalculateHDMapBound() {
390
  for (uint32_t i = 0; i < hdmap_bound_.size(); ++i) {
391 392
    double left_bound = 0.0;
    double right_bound = 0.0;
393 394
    bool suc = reference_line_.get_lane_width(evaluated_knots_[i], &left_bound,
                                              &right_bound);
395
    if (!suc) {
396
      AWARN << "Extracting lane width failed at s = " << evaluated_knots_[i];
397
      right_bound = FLAGS_default_reference_line_width / 2;
398
      left_bound = FLAGS_default_reference_line_width / 2;
399
    }
400

401 402 403 404 405
    hdmap_bound_[i].first = -right_bound + vehicle_param_.width() / 2;
    hdmap_bound_[i].second = left_bound - vehicle_param_.width() / 2;

    if (hdmap_bound_[i].first >= hdmap_bound_[i].second) {
      AERROR << "HD Map bound at " << evaluated_knots_[i] << " is infeasible ("
406 407
             << hdmap_bound_[i].first << ", " << hdmap_bound_[i].second << ") "
             << std::endl;
408
      feasible_longitudinal_upper_bound_ =
409
          std::min(evaluated_knots_[i], feasible_longitudinal_upper_bound_);
410
    }
411
  }
412 413
}

414
bool QpFrenetFrame::CalculateObstacleBound() {
Y
Yajia Zhang 已提交
415
  for (const auto ptr_path_obstacle : path_obstacles_) {
416 417 418
    if (!ptr_path_obstacle->HasLateralDecision()) {
      continue;
    }
Y
Yajia Zhang 已提交
419 420 421
    if (ptr_path_obstacle->Obstacle()->IsStatic()) {
      if (!MapStaticObstacleWithDecision(*ptr_path_obstacle)) {
        AERROR << "mapping obstacle with id [" << ptr_path_obstacle->Id()
422 423 424 425
               << "] failed in qp frenet frame.";
        return false;
      }
    } else {
Y
Yajia Zhang 已提交
426 427
      if (!MapDynamicObstacleWithDecision(*ptr_path_obstacle)) {
        AERROR << "mapping obstacle with id [" << ptr_path_obstacle->Id()
428 429 430
               << "] failed in qp frenet frame.";
        return false;
      }
D
Dong Li 已提交
431
    }
432 433 434 435
  }
  return true;
}

436
bool QpFrenetFrame::GetBound(
437
    const double s, const std::vector<std::pair<double, double>>& map_bound,
438
    std::pair<double, double>* const bound) const {
439 440
  if (Double::Compare(s, start_s_, 1e-8) < 0 ||
      Double::Compare(s, end_s_, 1e-8) > 0) {
441
    AERROR << "Evaluate s location " << s
442 443
           << ", is out of trajectory frenet frame range (" << start_s_ << ", "
           << end_s_ << ")";
D
Dong Li 已提交
444 445
    return false;
  }
446 447

  // linear bound interpolation
448
  uint32_t lower_index = FindIndex(s);
449 450
  const double s_low = evaluated_knots_[lower_index];
  const double s_high = evaluated_knots_[lower_index + 1];
451
  double weight = Double::Compare(s_low, s_high, 1e-8) < 0
452 453
                      ? (s - s_low) / (s_high - s_low)
                      : 0.0;
454

455 456 457 458
  double low_first = map_bound[lower_index].first;
  double low_second = map_bound[lower_index].second;
  double high_first = map_bound[lower_index + 1].first;
  double high_second = map_bound[lower_index + 1].second;
459

460 461
  // If there is only one infinity in low and high point, then make it equal
  // to
462 463 464 465 466 467 468 469 470 471 472 473 474
  // the not inf one.
  if (std::isinf(low_first) && !std::isinf(high_first)) {
    low_first = high_first;
  } else if (!std::isinf(low_first) && std::isinf(high_first)) {
    high_first = low_first;
  }

  if (std::isinf(low_second) && !std::isinf(high_second)) {
    low_second = high_second;
  } else if (!std::isinf(low_second) && std::isinf(high_second)) {
    high_second = low_second;
  }

475 476 477 478 479
  if (std::isinf(low_first)) {
    bound->first = low_first;
  } else {
    bound->first = low_first * (1 - weight) + high_first * weight;
  }
480

481 482 483
  if (std::isinf(low_second)) {
    bound->second = low_second * (1 - weight) + high_second * weight;
  }
484 485 486
  return true;
}

487
uint32_t QpFrenetFrame::FindIndex(const double s) const {
488
  auto lower_bound =
489
      std::lower_bound(evaluated_knots_.begin() + 1, evaluated_knots_.end(), s);
490
  return std::min(
491
             static_cast<uint32_t>(evaluated_knots_.size() - 1),
492 493
             static_cast<uint32_t>(lower_bound - evaluated_knots_.begin())) -
         1;
494 495 496
}

}  // namespace planning
D
Dong Li 已提交
497
}  // namespace apollo