qp_spline_st_graph.cc 17.1 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
#include "modules/planning/common/planning_gflags.h"
30

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

34 35
using apollo::common::ErrorCode;
using apollo::common::Status;
D
Dong Li 已提交
36
using apollo::common::VehicleParam;
A
Aaron Xiao 已提交
37
using apollo::planning_internal::STGraphDebug;
Z
Zhang Liangliang 已提交
38

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

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

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

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

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

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

85 86
  // initialize time resolution and
  Init();
Z
Zhang Liangliang 已提交
87

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

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

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

  // extract output
Z
Zhang Liangliang 已提交
110
  speed_data->Clear();
111
  const Spline1d& spline = spline_generator_->spline();
Z
Zhang Liangliang 已提交
112

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

125
  return Status::OK();
Z
Zhang Liangliang 已提交
126 127
}

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

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

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

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

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

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

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

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

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

201
  std::vector<double> speed_lower_bound(t_evaluated_.size(), 0.0);
202 203 204

  DCHECK_EQ(t_evaluated_.size(), speed_upper_bound.size());
  DCHECK_EQ(t_evaluated_.size(), speed_lower_bound.size());
205 206 207 208 209 210 211 212

  for (size_t i = 0; i < t_evaluated_.size(); ++i) {
    auto speed_constraint = st_graph_debug->mutable_speed_constraint()->Add();
    speed_constraint->add_t(t_evaluated_[i]);
    speed_constraint->add_lower_bound(speed_lower_bound[i]);
    speed_constraint->add_upper_bound(speed_upper_bound[i]);
  }

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

225
  // acceleration constraint
226 227
  constexpr double kAccelLowerBound = -4.5;
  constexpr double kAccelUpperBound = 2.0;
228 229 230
  std::vector<double> accel_lower_bound(t_evaluated_.size(), kAccelLowerBound);
  std::vector<double> accel_upper_bound(t_evaluated_.size(), kAccelUpperBound);

231 232 233 234 235 236 237 238 239 240 241 242
  constexpr double kInitPointAccelRelaxedRange = 1.0;
  if (init_point_.v() < kInitPointAccelRelaxedRange * 1.0) {
    accel_lower_bound.front() = init_point_.a() - kInitPointAccelRelaxedRange;
    accel_upper_bound.front() = init_point_.a() + kInitPointAccelRelaxedRange;
  } else if (!constraint->AddPointSecondDerivativeConstraint(0.0,
                                                             init_point_.a())) {
    const std::string msg =
        "add st start point acceleration constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

243 244 245 246 247 248 249
  DCHECK_EQ(t_evaluated_.size(), accel_lower_bound.size());
  DCHECK_EQ(t_evaluated_.size(), accel_upper_bound.size());
  if (!constraint->AddSecondDerivativeBoundary(t_evaluated_, accel_lower_bound,
                                               accel_upper_bound)) {
    const std::string msg = "Fail to apply acceleration constraints.";
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
250 251 252 253 254
  for (size_t i = 0; i < t_evaluated_.size(); ++i) {
    ADEBUG << "t_evaluated_: " << t_evaluated_[i]
           << "; accel_lower_bound: " << accel_lower_bound[i]
           << "; accel_upper_bound: " << accel_upper_bound[i];
  }
255

256
  return Status::OK();
Z
Zhang Liangliang 已提交
257 258
}

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

263
  if (qp_spline_st_speed_config_.speed_kernel_weight() > 0) {
264
    spline_kernel->AddDerivativeKernelMatrix(
265
        qp_spline_st_speed_config_.speed_kernel_weight());
Z
Zhang Liangliang 已提交
266 267
  }

268
  if (qp_spline_st_speed_config_.accel_kernel_weight() > 0) {
269
    spline_kernel->AddSecondOrderDerivativeMatrix(
270
        qp_spline_st_speed_config_.accel_kernel_weight());
Z
Zhang Liangliang 已提交
271 272
  }

273
  if (qp_spline_st_speed_config_.jerk_kernel_weight() > 0) {
274
    spline_kernel->AddThirdOrderDerivativeMatrix(
275
        qp_spline_st_speed_config_.jerk_kernel_weight());
Z
Zhang Liangliang 已提交
276 277
  }

278 279 280
  if (AddCruiseReferenceLineKernel(
          t_evaluated_, speed_limit,
          qp_spline_st_speed_config_.cruise_weight()) != Status::OK()) {
281 282 283
    return Status(ErrorCode::PLANNING_ERROR, "QpSplineStGraph::ApplyKernel");
  }

284 285 286
  if (AddFollowReferenceLineKernel(
          t_evaluated_, boundaries,
          qp_spline_st_speed_config_.follow_weight()) != Status::OK()) {
287
    return Status(ErrorCode::PLANNING_ERROR, "QpSplineStGraph::ApplyKernel");
288
  }
289 290 291 292
  return Status::OK();
}

Status QpSplineStGraph::Solve() {
293
  return spline_generator_->Solve()
294 295 296
             ? Status::OK()
             : Status(ErrorCode::PLANNING_ERROR, "QpSplineStGraph::solve");
}
297

298
Status QpSplineStGraph::AddCruiseReferenceLineKernel(
299 300
    const std::vector<double>& evaluate_t, const SpeedLimit& speed_limit,
    const double weight) {
Z
Zhang Liangliang 已提交
301
  auto* spline_kernel = spline_generator_->mutable_spline_kernel();
Z
Zhang Liangliang 已提交
302
  std::vector<double> s_vec;
303
  if (speed_limit.speed_limit_points().size() == 0) {
304 305 306
    std::string msg = "Fail to apply_kernel due to empty speed limits.";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
Z
Zhang Liangliang 已提交
307
  }
308
  double dist_ref = 0.0;
309
  s_vec.push_back(dist_ref);
310 311
  for (uint32_t i = 1; i < evaluate_t.size(); ++i) {
    dist_ref += (evaluate_t[i] - evaluate_t[i - 1]) *
312
                speed_limit.GetSpeedLimitByS(dist_ref);
313
    s_vec.push_back(dist_ref);
314
  }
315
  DCHECK_EQ(evaluate_t.size(), s_vec.size());
316

317 318
  for (std::size_t i = 0; i < evaluate_t.size(); ++i) {
    ADEBUG << "Cruise Ref S: " << s_vec[i]
319
           << " Relative time: " << evaluate_t[i] << std::endl;
320 321 322
  }

  if (evaluate_t.size() > 0) {
323
    spline_kernel->AddReferenceLineKernelMatrix(
324 325
        evaluate_t, s_vec,
        weight * qp_spline_st_speed_config_.total_time() / evaluate_t.size());
326 327
  }
  spline_kernel->AddRegularization(0.01);
Z
Zhang Liangliang 已提交
328
  return Status::OK();
Z
Zhang Liangliang 已提交
329 330
}

331
Status QpSplineStGraph::AddFollowReferenceLineKernel(
332
    const std::vector<double>& evaluate_t,
333
    const std::vector<StBoundary>& boundaries, const double weight) {
334 335
  auto* spline_kernel = spline_generator_->mutable_spline_kernel();
  std::vector<double> ref_s;
336 337
  std::vector<double> filtered_evaluate_t;
  for (const double curr_t : evaluate_t) {
338
    double s_min = std::numeric_limits<double>::infinity();
339 340
    bool success = false;
    for (const auto& boundary : boundaries) {
341
      if (boundary.boundary_type() != StBoundary::BoundaryType::FOLLOW) {
342 343 344 345 346
        continue;
      }
      double s_upper = 0.0;
      double s_lower = 0.0;
      if (boundary.GetUnblockSRange(curr_t, &s_upper, &s_lower)) {
347
        success = true;
348
        s_min = std::min(s_min, s_upper - boundary.characteristic_length());
349 350 351 352
      }
    }
    if (success) {
      filtered_evaluate_t.push_back(curr_t);
353
      ref_s.push_back(s_min);
354 355
    }
  }
356
  DCHECK_EQ(filtered_evaluate_t.size(), ref_s.size());
357

358
  if (!ref_s.empty()) {
359
    spline_kernel->AddReferenceLineKernelMatrix(
360 361
        filtered_evaluate_t, ref_s,
        weight * qp_spline_st_speed_config_.total_time() / evaluate_t.size());
362 363 364 365
  }

  for (std::size_t i = 0; i < filtered_evaluate_t.size(); ++i) {
    ADEBUG << "Follow Ref S: " << ref_s[i]
366
           << " Relative time: " << filtered_evaluate_t[i] << std::endl;
367
  }
368 369 370
  return Status::OK();
}

371
Status QpSplineStGraph::GetSConstraintByTime(
372
    const std::vector<StBoundary>& boundaries, const double time,
Z
Zhang Liangliang 已提交
373 374
    const double total_path_s, double* const s_upper_bound,
    double* const s_lower_bound) const {
375
  *s_upper_bound = total_path_s;
Z
Zhang Liangliang 已提交
376

377
  for (const StBoundary& boundary : boundaries) {
Z
Zhang Liangliang 已提交
378 379 380
    double s_upper = 0.0;
    double s_lower = 0.0;

381
    if (!boundary.GetUnblockSRange(time, &s_upper, &s_lower)) {
Z
Zhang Liangliang 已提交
382 383 384
      continue;
    }

385 386 387
    if (boundary.boundary_type() == StBoundary::BoundaryType::STOP ||
        boundary.boundary_type() == StBoundary::BoundaryType::FOLLOW ||
        boundary.boundary_type() == StBoundary::BoundaryType::YIELD) {
Z
Zhang Liangliang 已提交
388 389
      *s_upper_bound = std::fmin(*s_upper_bound, s_upper);
    } else {
390
      DCHECK(boundary.boundary_type() == StBoundary::BoundaryType::OVERTAKE);
Z
Zhang Liangliang 已提交
391 392 393 394
      *s_lower_bound = std::fmax(*s_lower_bound, s_lower);
    }
  }

395
  return Status::OK();
Z
Zhang Liangliang 已提交
396
}
397

398
Status QpSplineStGraph::EstimateSpeedUpperBound(
399
    const common::TrajectoryPoint& init_point, const SpeedLimit& speed_limit,
400 401
    std::vector<double>* speed_upper_bound) const {
  DCHECK_NOTNULL(speed_upper_bound);
402

403
  speed_upper_bound->clear();
404 405 406 407

  // 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.
408
  const double v = init_point.v();
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445

  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;
    };

446
    const auto& speed_limit_points = speed_limit.speed_limit_points();
447 448 449 450 451 452 453
    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()
      //
454 455
      // If either of the two assumption is failed, a new algorithm must be
      // used
456
      // to replace the binary search.
457 458 459 460 461 462 463 464

      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);
      }
465
    }
466
  }
467 468 469 470 471 472 473

  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));
  }
474

475 476 477
  return Status::OK();
}

Z
Zhang Liangliang 已提交
478 479
}  // namespace planning
}  // namespace apollo