qp_spline_st_graph.cc 16.3 KB
Newer Older
Z
Zhang Liangliang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/******************************************************************************
 * 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.
 *****************************************************************************/

/**
 * @file qp_spline_st_graph.cc
 **/

D
Dong Li 已提交
21
#include "modules/planning/tasks/qp_spline_st_speed/qp_spline_st_graph.h"
Z
Zhang Liangliang 已提交
22

A
Aaron Xiao 已提交
23
#include <algorithm>
24
#include <limits>
A
Aaron Xiao 已提交
25
#include <string>
A
Aaron Xiao 已提交
26 27
#include <utility>

Z
Zhang Liangliang 已提交
28
#include "modules/common/log.h"
29

Z
Zhang Liangliang 已提交
30 31 32
namespace apollo {
namespace planning {

33 34
using apollo::common::ErrorCode;
using apollo::common::Status;
D
Dong Li 已提交
35
using apollo::common::VehicleParam;
Z
Zhang Liangliang 已提交
36

37 38
QpSplineStGraph::QpSplineStGraph(
    const QpSplineStSpeedConfig& qp_spline_st_speed_config,
39
    const VehicleParam& veh_param)
40
    : qp_spline_st_speed_config_(qp_spline_st_speed_config),
41 42 43 44
      t_knots_resolution_(
          qp_spline_st_speed_config_.total_time() /
          qp_spline_st_speed_config_.number_of_discrete_graph_t()),
      t_evaluated_resolution_(
45
          qp_spline_st_speed_config_.total_time() /
46
          qp_spline_st_speed_config_.number_of_evaluated_graph_t()) {}
Z
Zhang Liangliang 已提交
47

48
void QpSplineStGraph::Init() {
49
  // init knots
50 51
  double curr_t = 0.0;
  for (uint32_t i = 0;
52
       i <= qp_spline_st_speed_config_.number_of_discrete_graph_t(); ++i) {
53
    t_knots_.push_back(curr_t);
54
    curr_t += t_knots_resolution_;
55
  }
56 57 58 59 60 61

  // init evaluated t positions
  curr_t = 0.0;
  for (uint32_t i = 0;
       i <= qp_spline_st_speed_config_.number_of_evaluated_graph_t(); ++i) {
    t_evaluated_.push_back(curr_t);
62
    curr_t += t_evaluated_resolution_;
63 64 65
  }

  // init spline generator
66 67
  spline_generator_.reset(new Spline1dGenerator(
      t_knots_, qp_spline_st_speed_config_.spline_order()));
68 69
}

70
Status QpSplineStGraph::Search(const StGraphData& st_graph_data,
71 72
                               const PathData& path_data,
                               SpeedData* const speed_data) {
73
  init_point_ = st_graph_data.init_point();
Z
Zhang Liangliang 已提交
74
  if (st_graph_data.path_data_length() <
75 76
      qp_spline_st_speed_config_.total_path_length()) {
    qp_spline_st_speed_config_.set_total_path_length(
Z
Zhang Liangliang 已提交
77 78 79
        st_graph_data.path_data_length());
  }

A
Aaron Xiao 已提交
80
  // TODO(all): update config through veh physical limit here generate knots
Z
Zhang Liangliang 已提交
81

82 83
  // initialize time resolution and
  Init();
Z
Zhang Liangliang 已提交
84

85
  if (!ApplyConstraint(st_graph_data.init_point(), st_graph_data.speed_limit(),
86
                       st_graph_data.st_boundaries())
87
           .ok()) {
88 89
    const std::string msg = "Apply constraint failed!";
    AERROR << msg;
90
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
91 92
  }

93
  if (!ApplyKernel(st_graph_data.st_boundaries(), st_graph_data.speed_limit())
94
           .ok()) {
95 96
    const std::string msg = "Apply kernel failed!";
    AERROR << msg;
97
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
98 99
  }

100
  if (!Solve().ok()) {
101 102
    const std::string msg = "Solve qp problem failed!";
    AERROR << msg;
103
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
104 105 106
  }

  // extract output
Z
Zhang Liangliang 已提交
107
  speed_data->Clear();
108
  const Spline1d& spline = spline_generator_->spline();
Z
Zhang Liangliang 已提交
109

110 111
  double t_output_resolution =
      qp_spline_st_speed_config_.output_time_resolution();
Z
Zhang Liangliang 已提交
112
  double time = 0.0;
113
  while (time < qp_spline_st_speed_config_.total_time() + t_output_resolution) {
Z
Zhang Liangliang 已提交
114
    double s = spline(time);
115 116 117
    double v = spline.Derivative(time);
    double a = spline.SecondOrderDerivative(time);
    double da = spline.ThirdOrderDerivative(time);
118
    speed_data->AppendSpeedPoint(s, time, v, a, da);
119
    time += t_output_resolution;
Z
Zhang Liangliang 已提交
120 121
  }

122
  return Status::OK();
Z
Zhang Liangliang 已提交
123 124
}

125
Status QpSplineStGraph::ApplyConstraint(
126
    const common::TrajectoryPoint& init_point, const SpeedLimit& speed_limit,
127
    const std::vector<StBoundary>& boundaries) {
Z
Zhang Liangliang 已提交
128
  Spline1dConstraint* constraint =
129
      spline_generator_->mutable_spline_constraint();
Z
Zhang Liangliang 已提交
130
  // position, velocity, acceleration
Z
Zhang Liangliang 已提交
131

132
  if (!constraint->AddPointConstraint(0.0, 0.0)) {
133 134
    const std::string msg = "add st start point constraint failed";
    AERROR << msg;
135
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
136
  }
137
  ADEBUG << "init point constraint:" << init_point.DebugString();
138
  if (!constraint->AddPointDerivativeConstraint(0.0, init_point_.v())) {
139 140
    const std::string msg = "add st start point velocity constraint failed!";
    AERROR << msg;
141
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
142 143
  }

144
  if (!constraint->AddPointSecondDerivativeConstraint(0.0, init_point_.a())) {
145 146
    const std::string msg =
        "add st start point acceleration constraint failed!";
147
    AERROR << msg;
148
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
149 150
  }

151
  if (!constraint->AddPointSecondDerivativeConstraint(
152
          spline_generator_->spline().x_knots().back(), 0.0)) {
153 154
    const std::string msg = "add st end point acceleration constraint failed!";
    AERROR << msg;
155
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
156 157 158
  }

  // monotone constraint
159
  if (!constraint->AddMonotoneInequalityConstraintAtKnots()) {
160
    const std::string msg = "add monotone inequality constraint failed!";
161
    AERROR << msg;
162
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
163 164 165
  }

  // smoothness constraint
166
  if (!constraint->AddThirdDerivativeSmoothConstraint()) {
167 168
    const std::string msg = "add smoothness joint constraint failed!";
    AERROR << msg;
169
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
170 171 172 173 174
  }

  // boundary constraint
  std::vector<double> s_upper_bound;
  std::vector<double> s_lower_bound;
175

176
  for (const double curr_t : t_evaluated_) {
Z
Zhang Liangliang 已提交
177 178
    double lower_s = 0.0;
    double upper_s = 0.0;
179 180 181
    GetSConstraintByTime(boundaries, curr_t,
                         qp_spline_st_speed_config_.total_path_length(),
                         &upper_s, &lower_s);
Z
Zhang Liangliang 已提交
182 183
    s_upper_bound.push_back(upper_s);
    s_lower_bound.push_back(lower_s);
184
    ADEBUG << "Add constraint by time: " << curr_t << " upper_s: " << upper_s
185
           << " lower_s: " << lower_s;
Z
Zhang Liangliang 已提交
186
  }
187 188 189

  DCHECK_EQ(t_evaluated_.size(), s_lower_bound.size());
  DCHECK_EQ(t_evaluated_.size(), s_upper_bound.size());
190
  if (!constraint->AddBoundary(t_evaluated_, s_lower_bound, s_upper_bound)) {
191
    const std::string msg = "Fail to apply distance constraints.";
192
    AERROR << msg;
193
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
194
  }
195

196
  // speed constraint
197 198
  std::vector<double> speed_upper_bound;
  if (!EstimateSpeedUpperBound(init_point, speed_limit, &speed_upper_bound)
199
           .ok()) {
200
    std::string msg = "Fail to estimate speed upper constraints.";
201 202 203
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
204 205

  std::vector<double> speed_lower_bound(t_evaluated_.size(), 0.0);
206 207 208

  DCHECK_EQ(t_evaluated_.size(), speed_upper_bound.size());
  DCHECK_EQ(t_evaluated_.size(), speed_lower_bound.size());
209
  if (!constraint->AddDerivativeBoundary(t_evaluated_, speed_lower_bound,
210
                                         speed_upper_bound)) {
211 212 213 214
    const std::string msg = "Fail to apply speed constraints.";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
215
  for (size_t i = 0; i < t_evaluated_.size(); ++i) {
216
    ADEBUG << "t_evaluated_: " << t_evaluated_[i]
217 218
           << "; speed_lower_bound: " << speed_lower_bound[i]
           << "; speed_upper_bound: " << speed_upper_bound[i] << std::endl;
219
  }
220

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
  // acceleration constraint
  constexpr double kAccelLowerBound = -3.5;
  constexpr double kAccelUpperBound = 1.5;
  std::vector<double> accel_lower_bound(t_evaluated_.size(), kAccelLowerBound);
  std::vector<double> accel_upper_bound(t_evaluated_.size(), kAccelUpperBound);

  DCHECK_EQ(t_evaluated_.size(), accel_lower_bound.size());
  DCHECK_EQ(t_evaluated_.size(), accel_upper_bound.size());
  // TODO: add accel constraint below
  /*
  if (!constraint->AddSecondDerivativeBoundary(t_evaluated_, accel_lower_bound,
                                               accel_upper_bound)) {
    const std::string msg = "Fail to apply acceleration constraints.";
    for (size_t i = 0; i < t_evaluated_.size(); ++i) {
      AERROR << "t_evaluated_: " << t_evaluated_[i]
             << "; accel_lower_bound: " << accel_lower_bound[i]
             << "; accel_upper_bound: " << accel_upper_bound[i] << std::endl;
    }
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
  */

243
  return Status::OK();
Z
Zhang Liangliang 已提交
244 245
}

246 247
Status QpSplineStGraph::ApplyKernel(const std::vector<StBoundary>& boundaries,
                                    const SpeedLimit& speed_limit) {
248
  Spline1dKernel* spline_kernel = spline_generator_->mutable_spline_kernel();
Z
Zhang Liangliang 已提交
249

250
  if (qp_spline_st_speed_config_.speed_kernel_weight() > 0) {
Z
Zhang Liangliang 已提交
251
    spline_kernel->add_derivative_kernel_matrix(
252
        qp_spline_st_speed_config_.speed_kernel_weight());
Z
Zhang Liangliang 已提交
253 254
  }

255
  if (qp_spline_st_speed_config_.accel_kernel_weight() > 0) {
Z
Zhang Liangliang 已提交
256
    spline_kernel->add_second_order_derivative_matrix(
257
        qp_spline_st_speed_config_.accel_kernel_weight());
Z
Zhang Liangliang 已提交
258 259
  }

260
  if (qp_spline_st_speed_config_.jerk_kernel_weight() > 0) {
Z
Zhang Liangliang 已提交
261
    spline_kernel->add_third_order_derivative_matrix(
262
        qp_spline_st_speed_config_.jerk_kernel_weight());
Z
Zhang Liangliang 已提交
263 264
  }

265 266 267
  if (AddCruiseReferenceLineKernel(
          t_evaluated_, speed_limit,
          qp_spline_st_speed_config_.cruise_weight()) != Status::OK()) {
268 269 270
    return Status(ErrorCode::PLANNING_ERROR, "QpSplineStGraph::ApplyKernel");
  }

271 272 273
  if (AddFollowReferenceLineKernel(
          t_evaluated_, boundaries,
          qp_spline_st_speed_config_.follow_weight()) != Status::OK()) {
274
    return Status(ErrorCode::PLANNING_ERROR, "QpSplineStGraph::ApplyKernel");
275
  }
276 277 278 279
  return Status::OK();
}

Status QpSplineStGraph::Solve() {
280
  return spline_generator_->Solve()
281 282 283
             ? Status::OK()
             : Status(ErrorCode::PLANNING_ERROR, "QpSplineStGraph::solve");
}
284

285
Status QpSplineStGraph::AddCruiseReferenceLineKernel(
286 287
    const std::vector<double>& evaluate_t, const SpeedLimit& speed_limit,
    const double weight) {
Z
Zhang Liangliang 已提交
288
  auto* spline_kernel = spline_generator_->mutable_spline_kernel();
Z
Zhang Liangliang 已提交
289
  std::vector<double> s_vec;
290
  if (speed_limit.speed_limit_points().size() == 0) {
291 292 293
    std::string msg = "Fail to apply_kernel due to empty speed limits.";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
294
  }
295
  double dist_ref = 0.0;
296
  s_vec.push_back(dist_ref);
297 298
  for (uint32_t i = 1; i < evaluate_t.size(); ++i) {
    dist_ref += (evaluate_t[i] - evaluate_t[i - 1]) *
299
                speed_limit.GetSpeedLimitByS(dist_ref);
300
    s_vec.push_back(dist_ref);
301
  }
302
  DCHECK_EQ(evaluate_t.size(), s_vec.size());
303

304 305
  for (std::size_t i = 0; i < evaluate_t.size(); ++i) {
    ADEBUG << "Cruise Ref S: " << s_vec[i]
306
           << " Relative time: " << evaluate_t[i] << std::endl;
307 308 309 310
  }

  if (evaluate_t.size() > 0) {
    spline_kernel->add_reference_line_kernel_matrix(
311 312
        evaluate_t, s_vec,
        weight * qp_spline_st_speed_config_.total_time() / evaluate_t.size());
313 314
  }
  spline_kernel->AddRegularization(0.01);
Z
Zhang Liangliang 已提交
315
  return Status::OK();
Z
Zhang Liangliang 已提交
316 317
}

318
Status QpSplineStGraph::AddFollowReferenceLineKernel(
319
    const std::vector<double>& evaluate_t,
320
    const std::vector<StBoundary>& boundaries, const double weight) {
321 322
  auto* spline_kernel = spline_generator_->mutable_spline_kernel();
  std::vector<double> ref_s;
323 324
  std::vector<double> filtered_evaluate_t;
  for (const double curr_t : evaluate_t) {
325
    double s_min = std::numeric_limits<double>::infinity();
326 327
    bool success = false;
    for (const auto& boundary : boundaries) {
328
      if (boundary.boundary_type() != StBoundary::BoundaryType::FOLLOW) {
329 330 331 332 333
        continue;
      }
      double s_upper = 0.0;
      double s_lower = 0.0;
      if (boundary.GetUnblockSRange(curr_t, &s_upper, &s_lower)) {
334
        success = true;
335
        s_min = std::min(s_min, s_upper - boundary.characteristic_length());
336 337 338 339
      }
    }
    if (success) {
      filtered_evaluate_t.push_back(curr_t);
340
      ref_s.push_back(s_min);
341 342
    }
  }
343
  DCHECK_EQ(filtered_evaluate_t.size(), ref_s.size());
344

345
  if (!ref_s.empty()) {
346
    spline_kernel->add_reference_line_kernel_matrix(
347 348
        filtered_evaluate_t, ref_s,
        weight * qp_spline_st_speed_config_.total_time() / evaluate_t.size());
349 350 351 352
  }

  for (std::size_t i = 0; i < filtered_evaluate_t.size(); ++i) {
    ADEBUG << "Follow Ref S: " << ref_s[i]
353
           << " Relative time: " << filtered_evaluate_t[i] << std::endl;
354
  }
355 356 357
  return Status::OK();
}

358
Status QpSplineStGraph::GetSConstraintByTime(
359
    const std::vector<StBoundary>& boundaries, const double time,
Z
Zhang Liangliang 已提交
360 361
    const double total_path_s, double* const s_upper_bound,
    double* const s_lower_bound) const {
362
  *s_upper_bound = total_path_s;
Z
Zhang Liangliang 已提交
363

364
  for (const StBoundary& boundary : boundaries) {
Z
Zhang Liangliang 已提交
365 366 367
    double s_upper = 0.0;
    double s_lower = 0.0;

368
    if (!boundary.GetUnblockSRange(time, &s_upper, &s_lower)) {
Z
Zhang Liangliang 已提交
369 370 371
      continue;
    }

372 373 374
    if (boundary.boundary_type() == StBoundary::BoundaryType::STOP ||
        boundary.boundary_type() == StBoundary::BoundaryType::FOLLOW ||
        boundary.boundary_type() == StBoundary::BoundaryType::YIELD) {
Z
Zhang Liangliang 已提交
375 376
      *s_upper_bound = std::fmin(*s_upper_bound, s_upper);
    } else {
377
      DCHECK(boundary.boundary_type() == StBoundary::BoundaryType::OVERTAKE);
Z
Zhang Liangliang 已提交
378 379 380 381
      *s_lower_bound = std::fmax(*s_lower_bound, s_lower);
    }
  }

382
  return Status::OK();
Z
Zhang Liangliang 已提交
383
}
384

385
Status QpSplineStGraph::EstimateSpeedUpperBound(
386
    const common::TrajectoryPoint& init_point, const SpeedLimit& speed_limit,
387 388
    std::vector<double>* speed_upper_bound) const {
  DCHECK_NOTNULL(speed_upper_bound);
389

390
  speed_upper_bound->clear();
391 392 393 394

  // use v to estimate position: not accurate, but feasible in cyclic
  // processing. We can do the following process multiple times and use
  // previous cycle's results for better estimation.
395
  const double v = init_point.v();
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432

  if (static_cast<double>(t_evaluated_.size() +
                          speed_limit.speed_limit_points().size()) <
      t_evaluated_.size() * std::log(static_cast<double>(
                                speed_limit.speed_limit_points().size()))) {
    uint32_t i = 0;
    uint32_t j = 0;
    const double kDistanceEpsilon = 1e-6;
    while (i < t_evaluated_.size() &&
           j + 1 < speed_limit.speed_limit_points().size()) {
      const double distance = v * t_evaluated_[i];
      if (fabs(distance - speed_limit.speed_limit_points()[j].first) <
          kDistanceEpsilon) {
        speed_upper_bound->push_back(
            speed_limit.speed_limit_points()[j].second);
        ++i;
        ADEBUG << "speed upper bound:" << speed_upper_bound->back();
      } else if (distance < speed_limit.speed_limit_points()[j].first) {
        ++i;
      } else if (distance <= speed_limit.speed_limit_points()[j + 1].first) {
        speed_upper_bound->push_back(speed_limit.GetSpeedLimitByS(distance));
        ADEBUG << "speed upper bound:" << speed_upper_bound->back();
        ++i;
      } else {
        ++j;
      }
    }

    for (uint32_t k = speed_upper_bound->size(); k < t_evaluated_.size(); ++k) {
      speed_upper_bound->push_back(qp_spline_st_speed_config_.max_speed());
      ADEBUG << "speed upper bound:" << speed_upper_bound->back();
    }
  } else {
    auto cmp = [](const std::pair<double, double>& p1, const double s) {
      return p1.first < s;
    };

433
    const auto& speed_limit_points = speed_limit.speed_limit_points();
434 435 436 437 438 439 440
    for (const double t : t_evaluated_) {
      const double s = v * t;

      // NOTICE: we are using binary search here based on two assumptions:
      // (1) The s in speed_limit_points increase monotonically.
      // (2) The evaluated_t_.size() << number of speed_limit_points.size()
      //
441 442
      // If either of the two assumption is failed, a new algorithm must be
      // used
443
      // to replace the binary search.
444 445 446 447 448 449 450 451

      const auto& it = std::lower_bound(speed_limit_points.begin(),
                                        speed_limit_points.end(), s, cmp);
      if (it != speed_limit_points.end()) {
        speed_upper_bound->push_back(it->second);
      } else {
        speed_upper_bound->push_back(speed_limit_points.back().second);
      }
452
    }
453
  }
454 455 456 457 458 459 460

  const double kTimeBuffer = 2.0;
  for (uint32_t k = 0; k < t_evaluated_.size() && t_evaluated_[k] < kTimeBuffer;
       ++k) {
    speed_upper_bound->at(k) =
        std::fmax(init_point_.v(), speed_upper_bound->at(k));
  }
461

462 463 464
  return Status::OK();
}

Z
Zhang Liangliang 已提交
465 466
}  // namespace planning
}  // namespace apollo