Apollo 11.0
自动驾驶开放平台
piecewise_jerk_problem.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
18
19#include "cyber/common/log.h"
21
22namespace apollo {
23namespace planning {
24
25namespace {
26constexpr double kMaxVariableRange = 1.0e10;
27} // namespace
28
30 const size_t num_of_knots, const double delta_s,
31 const std::array<double, 3>& x_init) {
32 CHECK_GE(num_of_knots, 2U);
33 num_of_knots_ = num_of_knots;
34
35 x_init_ = x_init;
36
37 delta_s_ = delta_s;
38
40 std::make_pair(-kMaxVariableRange, kMaxVariableRange));
41
43 std::make_pair(-kMaxVariableRange, kMaxVariableRange));
44
46 std::make_pair(-kMaxVariableRange, kMaxVariableRange));
47
48 weight_x_ref_vec_ = std::vector<double>(num_of_knots_, 0.0);
49}
50
52 // calculate kernel
53 std::vector<c_float> P_data;
54 std::vector<c_int> P_indices;
55 std::vector<c_int> P_indptr;
56 CalculateKernel(&P_data, &P_indices, &P_indptr);
57
58 // calculate affine constraints
59 std::vector<c_float> A_data;
60 std::vector<c_int> A_indices;
61 std::vector<c_int> A_indptr;
62 std::vector<c_float> lower_bounds;
63 std::vector<c_float> upper_bounds;
64 CalculateAffineConstraint(&A_data, &A_indices, &A_indptr, &lower_bounds,
65 &upper_bounds);
66
67 // calculate offset
68 std::vector<c_float> q;
70
71 CHECK_EQ(lower_bounds.size(), upper_bounds.size());
72
73 size_t kernel_dim = 3 * num_of_knots_;
74 size_t num_affine_constraint = lower_bounds.size();
75
76 data->n = kernel_dim;
77 data->m = num_affine_constraint;
78 data->P = csc_matrix(kernel_dim, kernel_dim, P_data.size(), CopyData(P_data),
79 CopyData(P_indices), CopyData(P_indptr));
80 data->q = CopyData(q);
81 data->A =
82 csc_matrix(num_affine_constraint, kernel_dim, A_data.size(),
83 CopyData(A_data), CopyData(A_indices), CopyData(A_indptr));
84 data->l = CopyData(lower_bounds);
85 data->u = CopyData(upper_bounds);
86
87 return CheckLowUpperBound(lower_bounds, upper_bounds);
88}
89
90bool PiecewiseJerkProblem::Optimize(const int max_iter) {
91 OSQPData* data = reinterpret_cast<OSQPData*>(c_malloc(sizeof(OSQPData)));
92 if (FormulateProblem(data)) {
93 FreeData(data);
94 return false;
95 }
96 OSQPSettings* settings = SolverDefaultSettings();
97 settings->max_iter = max_iter;
98 OSQPWorkspace* osqp_work = nullptr;
99 osqp_work = osqp_setup(data, settings);
100 // osqp_setup(&osqp_work, data, settings);
101 osqp_solve(osqp_work);
102 auto status = osqp_work->info->status_val;
103
104 if (status < 0 || (status != 1 && status != 2)) {
105 AERROR << "failed optimization status:\t" << osqp_work->info->status;
106 osqp_cleanup(osqp_work);
107 FreeData(data);
108 c_free(settings);
109 return false;
110 } else if (osqp_work->solution == nullptr) {
111 AERROR << "The solution from OSQP is nullptr";
112 osqp_cleanup(osqp_work);
113 FreeData(data);
114 c_free(settings);
115 return false;
116 }
117
118 // extract primal results
119 x_.resize(num_of_knots_);
120 dx_.resize(num_of_knots_);
121 ddx_.resize(num_of_knots_);
122 for (size_t i = 0; i < num_of_knots_; ++i) {
123 x_.at(i) = osqp_work->solution->x[i] / scale_factor_[0];
124 dx_.at(i) = osqp_work->solution->x[i + num_of_knots_] / scale_factor_[1];
125 ddx_.at(i) =
126 osqp_work->solution->x[i + 2 * num_of_knots_] / scale_factor_[2];
127 }
128
129 // Cleanup
130 osqp_cleanup(osqp_work);
131 FreeData(data);
132 c_free(settings);
133 return true;
134}
135
137 std::vector<c_float>* A_data, std::vector<c_int>* A_indices,
138 std::vector<c_int>* A_indptr, std::vector<c_float>* lower_bounds,
139 std::vector<c_float>* upper_bounds) {
140 // 3N params bounds on x, x', x''
141 // 3(N-1) constraints on x, x', x''
142 // 3 constraints on x_init_
143 const int n = static_cast<int>(num_of_knots_);
144 const int num_of_variables = 3 * n;
145 const int num_of_constraints = num_of_variables + 3 * (n - 1) + 3;
146 lower_bounds->resize(num_of_constraints);
147 upper_bounds->resize(num_of_constraints);
148
149 std::vector<std::vector<std::pair<c_int, c_float>>> variables(
150 num_of_variables);
151
152 int constraint_index = 0;
153 // set x, x', x'' bounds
154 for (int i = 0; i < num_of_variables; ++i) {
155 if (i < n) {
156 variables[i].emplace_back(constraint_index, 1.0);
157 lower_bounds->at(constraint_index) =
158 x_bounds_[i].first * scale_factor_[0];
159 upper_bounds->at(constraint_index) =
160 x_bounds_[i].second * scale_factor_[0];
161 } else if (i < 2 * n) {
162 variables[i].emplace_back(constraint_index, 1.0);
163
164 lower_bounds->at(constraint_index) =
165 dx_bounds_[i - n].first * scale_factor_[1];
166 upper_bounds->at(constraint_index) =
167 dx_bounds_[i - n].second * scale_factor_[1];
168 } else {
169 variables[i].emplace_back(constraint_index, 1.0);
170 lower_bounds->at(constraint_index) =
171 ddx_bounds_[i - 2 * n].first * scale_factor_[2];
172 upper_bounds->at(constraint_index) =
173 ddx_bounds_[i - 2 * n].second * scale_factor_[2];
174 }
175 ++constraint_index;
176 }
177 CHECK_EQ(constraint_index, num_of_variables);
178
179 // x(i->i+1)''' = (x(i+1)'' - x(i)'') / delta_s
180 for (int i = 0; i + 1 < n; ++i) {
181 variables[2 * n + i].emplace_back(constraint_index, -1.0);
182 variables[2 * n + i + 1].emplace_back(constraint_index, 1.0);
183 lower_bounds->at(constraint_index) =
185 upper_bounds->at(constraint_index) =
186 dddx_bound_.second * delta_s_ * scale_factor_[2];
187 ++constraint_index;
188 }
189
190 // x(i+1)' - x(i)' - 0.5 * delta_s * x(i)'' - 0.5 * delta_s * x(i+1)'' = 0
191 for (int i = 0; i + 1 < n; ++i) {
192 variables[n + i].emplace_back(constraint_index, -1.0 * scale_factor_[2]);
193 variables[n + i + 1].emplace_back(constraint_index, 1.0 * scale_factor_[2]);
194 variables[2 * n + i].emplace_back(constraint_index,
195 -0.5 * delta_s_ * scale_factor_[1]);
196 variables[2 * n + i + 1].emplace_back(constraint_index,
197 -0.5 * delta_s_ * scale_factor_[1]);
198 lower_bounds->at(constraint_index) = 0.0;
199 upper_bounds->at(constraint_index) = 0.0;
200 ++constraint_index;
201 }
202
203 // x(i+1) - x(i) - delta_s * x(i)'
204 // - 1/3 * delta_s^2 * x(i)'' - 1/6 * delta_s^2 * x(i+1)''
205 auto delta_s_sq_ = delta_s_ * delta_s_;
206 for (int i = 0; i + 1 < n; ++i) {
207 variables[i].emplace_back(constraint_index,
208 -1.0 * scale_factor_[1] * scale_factor_[2]);
209 variables[i + 1].emplace_back(constraint_index,
210 1.0 * scale_factor_[1] * scale_factor_[2]);
211 variables[n + i].emplace_back(
212 constraint_index, -delta_s_ * scale_factor_[0] * scale_factor_[2]);
213 variables[2 * n + i].emplace_back(
214 constraint_index,
215 -delta_s_sq_ / 3.0 * scale_factor_[0] * scale_factor_[1]);
216 variables[2 * n + i + 1].emplace_back(
217 constraint_index,
218 -delta_s_sq_ / 6.0 * scale_factor_[0] * scale_factor_[1]);
219
220 lower_bounds->at(constraint_index) = 0.0;
221 upper_bounds->at(constraint_index) = 0.0;
222 ++constraint_index;
223 }
224
225 // constrain on x_init
226 variables[0].emplace_back(constraint_index, 1.0);
227 lower_bounds->at(constraint_index) = x_init_[0] * scale_factor_[0];
228 upper_bounds->at(constraint_index) = x_init_[0] * scale_factor_[0];
229 ++constraint_index;
230
231 variables[n].emplace_back(constraint_index, 1.0);
232 lower_bounds->at(constraint_index) = x_init_[1] * scale_factor_[1];
233 upper_bounds->at(constraint_index) = x_init_[1] * scale_factor_[1];
234 ++constraint_index;
235
236 variables[2 * n].emplace_back(constraint_index, 1.0);
237 lower_bounds->at(constraint_index) = x_init_[2] * scale_factor_[2];
238 upper_bounds->at(constraint_index) = x_init_[2] * scale_factor_[2];
239 ++constraint_index;
240
241 CHECK_EQ(constraint_index, num_of_constraints);
242
243 int ind_p = 0;
244 for (int i = 0; i < num_of_variables; ++i) {
245 A_indptr->push_back(ind_p);
246 for (const auto& variable_nz : variables[i]) {
247 // coefficient
248 A_data->push_back(variable_nz.second);
249
250 // constraint index
251 A_indices->push_back(variable_nz.first);
252 ++ind_p;
253 }
254 }
255 // We indeed need this line because of
256 // https://github.com/oxfordcontrol/osqp/blob/master/src/cs.c#L255
257 A_indptr->push_back(ind_p);
258}
259
261 // Define Solver default settings
262 OSQPSettings* settings =
263 reinterpret_cast<OSQPSettings*>(c_malloc(sizeof(OSQPSettings)));
264 osqp_set_default_settings(settings);
265 settings->polish = true;
266 settings->verbose = FLAGS_enable_osqp_debug;
267 settings->scaled_termination = true;
268 return settings;
269}
270
272 std::vector<std::pair<double, double>> x_bounds) {
273 CHECK_EQ(x_bounds.size(), num_of_knots_);
274 x_bounds_ = std::move(x_bounds);
275}
276
278 std::vector<std::pair<double, double>> dx_bounds) {
279 CHECK_EQ(dx_bounds.size(), num_of_knots_);
280 dx_bounds_ = std::move(dx_bounds);
281}
282
284 std::vector<std::pair<double, double>> ddx_bounds) {
285 CHECK_EQ(ddx_bounds.size(), num_of_knots_);
286 ddx_bounds_ = std::move(ddx_bounds);
287}
288
289void PiecewiseJerkProblem::set_x_bounds(const double x_lower_bound,
290 const double x_upper_bound) {
291 for (auto& x : x_bounds_) {
292 x.first = x_lower_bound;
293 x.second = x_upper_bound;
294 }
295}
296
297void PiecewiseJerkProblem::set_dx_bounds(const double dx_lower_bound,
298 const double dx_upper_bound) {
299 for (auto& x : dx_bounds_) {
300 x.first = dx_lower_bound;
301 x.second = dx_upper_bound;
302 }
303}
304
305void PiecewiseJerkProblem::set_ddx_bounds(const double ddx_lower_bound,
306 const double ddx_upper_bound) {
307 for (auto& x : ddx_bounds_) {
308 x.first = ddx_lower_bound;
309 x.second = ddx_upper_bound;
310 }
311}
312
313void PiecewiseJerkProblem::set_x_ref(const double weight_x_ref,
314 std::vector<double> x_ref) {
315 CHECK_EQ(x_ref.size(), num_of_knots_);
316 weight_x_ref_ = weight_x_ref;
317 // set uniform weighting
318 weight_x_ref_vec_ = std::vector<double>(num_of_knots_, weight_x_ref);
319 x_ref_ = std::move(x_ref);
320 has_x_ref_ = true;
321}
322
323void PiecewiseJerkProblem::set_x_ref(std::vector<double> weight_x_ref_vec,
324 std::vector<double> x_ref) {
325 CHECK_EQ(x_ref.size(), num_of_knots_);
326 CHECK_EQ(weight_x_ref_vec.size(), num_of_knots_);
327 // set piecewise weighting
328 weight_x_ref_vec_ = std::move(weight_x_ref_vec);
329 x_ref_ = std::move(x_ref);
330 has_x_ref_ = true;
331}
332
333void PiecewiseJerkProblem::set_towing_x_ref(const double weight_towing_x_ref,
334 std::vector<double> towing_x_ref) {
335 CHECK_EQ(towing_x_ref.size(), num_of_knots_);
337 std::vector<double>(num_of_knots_, weight_towing_x_ref);
338 towing_x_ref_ = std::move(towing_x_ref);
339 has_towing_x_ref_ = true;
340}
341
343 std::vector<double> weight_towing_x_ref_vec,
344 std::vector<double> towing_x_ref) {
345 CHECK_EQ(towing_x_ref.size(), num_of_knots_);
346 CHECK_EQ(weight_towing_x_ref_vec.size(), num_of_knots_);
347 weight_towing_x_ref_vec_ = std::move(weight_towing_x_ref_vec);
348 towing_x_ref_ = std::move(towing_x_ref);
349 has_towing_x_ref_ = true;
350}
351
353 const std::array<double, 3>& weight_end_state,
354 const std::array<double, 3>& end_state_ref) {
355 weight_end_state_ = weight_end_state;
356 end_state_ref_ = end_state_ref;
357 has_end_state_ref_ = true;
358}
359
360void PiecewiseJerkProblem::FreeData(OSQPData* data) {
361 delete[] data->q;
362 delete[] data->l;
363 delete[] data->u;
364
365 delete[] data->P->i;
366 delete[] data->P->p;
367 delete[] data->P->x;
368
369 delete[] data->A->i;
370 delete[] data->A->p;
371 delete[] data->A->x;
372}
373
375 const std::vector<c_float>& lower, const std::vector<c_float>& upper) {
376 for (size_t i = 0; i < lower.size(); i++) {
377 if (lower[i] > upper[i]) {
378 return true;
379 }
380 }
381 return false;
382}
383
384} // namespace planning
385} // namespace apollo
bool CheckLowUpperBound(const std::vector< c_float > &lower, const std::vector< c_float > &upper)
void set_x_ref(const double weight_x_ref, std::vector< double > x_ref)
Set the x ref object and the uniform x_ref weighting
std::vector< std::pair< double, double > > x_bounds_
virtual void CalculateKernel(std::vector< c_float > *P_data, std::vector< c_int > *P_indices, std::vector< c_int > *P_indptr)=0
PiecewiseJerkProblem(const size_t num_of_knots, const double delta_s, const std::array< double, 3 > &x_init)
T * CopyData(const std::vector< T > &vec)
void set_end_state_ref(const std::array< double, 3 > &weight_end_state, const std::array< double, 3 > &end_state_ref)
virtual void CalculateOffset(std::vector< c_float > *q)=0
void set_x_bounds(std::vector< std::pair< double, double > > x_bounds)
virtual bool Optimize(const int max_iter=4000)
void set_dx_bounds(std::vector< std::pair< double, double > > dx_bounds)
void set_towing_x_ref(const double weight_towing_x_ref, std::vector< double > towing_x_ref)
Set towing x ref object and piecewised towing_x_ref weightings
std::vector< std::pair< double, double > > ddx_bounds_
virtual void CalculateAffineConstraint(std::vector< c_float > *A_data, std::vector< c_int > *A_indices, std::vector< c_int > *A_indptr, std::vector< c_float > *lower_bounds, std::vector< c_float > *upper_bounds)
std::vector< std::pair< double, double > > dx_bounds_
void set_ddx_bounds(std::vector< std::pair< double, double > > ddx_bounds)
Planning module main class.
#define AERROR
Definition log.h:44
class register implement
Definition arena_queue.h:37