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
  // 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 240
  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);
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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