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->AddSecondDerivativeSmoothConstraint()) {
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
  // acceleration constraint
222
  constexpr double kAccelLowerBound = -4.0;
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
  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());
  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);
  }

240
  return Status::OK();
Z
Zhang Liangliang 已提交
241 242
}

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

247
  if (qp_spline_st_speed_config_.speed_kernel_weight() > 0) {
Z
Zhang Liangliang 已提交
248
    spline_kernel->add_derivative_kernel_matrix(
249
        qp_spline_st_speed_config_.speed_kernel_weight());
Z
Zhang Liangliang 已提交
250 251
  }

252
  if (qp_spline_st_speed_config_.accel_kernel_weight() > 0) {
Z
Zhang Liangliang 已提交
253
    spline_kernel->add_second_order_derivative_matrix(
254
        qp_spline_st_speed_config_.accel_kernel_weight());
Z
Zhang Liangliang 已提交
255 256
  }

257
  if (qp_spline_st_speed_config_.jerk_kernel_weight() > 0) {
Z
Zhang Liangliang 已提交
258
    spline_kernel->add_third_order_derivative_matrix(
259
        qp_spline_st_speed_config_.jerk_kernel_weight());
Z
Zhang Liangliang 已提交
260 261
  }

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

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

Status QpSplineStGraph::Solve() {
277
  return spline_generator_->Solve()
278 279 280
             ? Status::OK()
             : Status(ErrorCode::PLANNING_ERROR, "QpSplineStGraph::solve");
}
281

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

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

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

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

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

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

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

361
  for (const StBoundary& boundary : boundaries) {
Z
Zhang Liangliang 已提交
362 363 364
    double s_upper = 0.0;
    double s_lower = 0.0;

365
    if (!boundary.GetUnblockSRange(time, &s_upper, &s_lower)) {
Z
Zhang Liangliang 已提交
366 367 368
      continue;
    }

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

379
  return Status::OK();
Z
Zhang Liangliang 已提交
380
}
381

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

387
  speed_upper_bound->clear();
388 389 390 391

  // 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.
392
  const double v = init_point.v();
393 394 395 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

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

430
    const auto& speed_limit_points = speed_limit.speed_limit_points();
431 432 433 434 435 436 437
    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()
      //
438 439
      // If either of the two assumption is failed, a new algorithm must be
      // used
440
      // to replace the binary search.
441 442 443 444 445 446 447 448

      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);
      }
449
    }
450
  }
451 452 453 454 455 456 457

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

459 460 461
  return Status::OK();
}

Z
Zhang Liangliang 已提交
462 463
}  // namespace planning
}  // namespace apollo