qp_spline_st_graph.cc 16.8 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;
A
Aaron Xiao 已提交
36
using apollo::planning_internal::STGraphDebug;
Z
Zhang Liangliang 已提交
37

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

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

  // 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);
63
    curr_t += t_evaluated_resolution_;
64 65 66
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

207 208 209
  constexpr double kSpeedBoundEpsilon = 1e-12;
  std::vector<double> speed_lower_bound(t_evaluated_.size(),
                                        kSpeedBoundEpsilon);
210 211 212

  DCHECK_EQ(t_evaluated_.size(), speed_upper_bound.size());
  DCHECK_EQ(t_evaluated_.size(), speed_lower_bound.size());
213 214 215 216 217 218 219 220 221


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

222
  if (!constraint->AddDerivativeBoundary(t_evaluated_, speed_lower_bound,
223
                                         speed_upper_bound)) {
224 225 226 227
    const std::string msg = "Fail to apply speed constraints.";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
228
  for (size_t i = 0; i < t_evaluated_.size(); ++i) {
229
    ADEBUG << "t_evaluated_: " << t_evaluated_[i]
230 231
           << "; speed_lower_bound: " << speed_lower_bound[i]
           << "; speed_upper_bound: " << speed_upper_bound[i] << std::endl;
232
  }
233

234
  // acceleration constraint
235
  constexpr double kAccelLowerBound = -4.0;
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
  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);
  }

253
  return Status::OK();
Z
Zhang Liangliang 已提交
254 255
}

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

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

265
  if (qp_spline_st_speed_config_.accel_kernel_weight() > 0) {
Z
Zhang Liangliang 已提交
266
    spline_kernel->add_second_order_derivative_matrix(
267
        qp_spline_st_speed_config_.accel_kernel_weight());
Z
Zhang Liangliang 已提交
268 269
  }

270
  if (qp_spline_st_speed_config_.jerk_kernel_weight() > 0) {
Z
Zhang Liangliang 已提交
271
    spline_kernel->add_third_order_derivative_matrix(
272
        qp_spline_st_speed_config_.jerk_kernel_weight());
Z
Zhang Liangliang 已提交
273 274
  }

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

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

Status QpSplineStGraph::Solve() {
290
  return spline_generator_->Solve()
291 292 293
             ? Status::OK()
             : Status(ErrorCode::PLANNING_ERROR, "QpSplineStGraph::solve");
}
294

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

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

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

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

355
  if (!ref_s.empty()) {
356
    spline_kernel->add_reference_line_kernel_matrix(
357 358
        filtered_evaluate_t, ref_s,
        weight * qp_spline_st_speed_config_.total_time() / evaluate_t.size());
359 360 361 362
  }

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

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

374
  for (const StBoundary& boundary : boundaries) {
Z
Zhang Liangliang 已提交
375 376 377
    double s_upper = 0.0;
    double s_lower = 0.0;

378
    if (!boundary.GetUnblockSRange(time, &s_upper, &s_lower)) {
Z
Zhang Liangliang 已提交
379 380 381
      continue;
    }

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

392
  return Status::OK();
Z
Zhang Liangliang 已提交
393
}
394

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

400
  speed_upper_bound->clear();
401 402 403 404

  // 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.
405
  const double v = init_point.v();
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 433 434 435 436 437 438 439 440 441 442

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

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

      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);
      }
462
    }
463
  }
464 465 466 467 468 469 470

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

472 473 474
  return Status::OK();
}

Z
Zhang Liangliang 已提交
475 476
}  // namespace planning
}  // namespace apollo