Apollo 11.0
自动驾驶开放平台
fem_pos_deviation_osqp_interface.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2019 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
22
23#include <limits>
24
25#include "cyber/common/log.h"
26
27namespace apollo {
28namespace planning {
29
31 // Sanity Check
32 if (ref_points_.empty()) {
33 AERROR << "reference points empty, solver early terminates";
34 return false;
35 }
36
37 if (ref_points_.size() != bounds_around_refs_.size()) {
38 AERROR << "ref_points and bounds size not equal, solver early terminates";
39 return false;
40 }
41
42 if (ref_points_.size() < 3) {
43 AERROR << "ref_points size smaller than 3, solver early terminates";
44 return false;
45 }
46
47 if (ref_points_.size() > std::numeric_limits<int>::max()) {
48 AERROR << "ref_points size too large, solver early terminates";
49 return false;
50 }
51
52 // Calculate optimization states definitions
53 num_of_points_ = static_cast<int>(ref_points_.size());
54 num_of_variables_ = num_of_points_ * 2;
55 num_of_constraints_ = num_of_variables_;
56
57 // Calculate kernel
58 std::vector<c_float> P_data;
59 std::vector<c_int> P_indices;
60 std::vector<c_int> P_indptr;
61 CalculateKernel(&P_data, &P_indices, &P_indptr);
62
63 // Calculate affine constraints
64 std::vector<c_float> A_data;
65 std::vector<c_int> A_indices;
66 std::vector<c_int> A_indptr;
67 std::vector<c_float> lower_bounds;
68 std::vector<c_float> upper_bounds;
69 CalculateAffineConstraint(&A_data, &A_indices, &A_indptr, &lower_bounds,
70 &upper_bounds);
71
72 // Calculate offset
73 std::vector<c_float> q;
74 CalculateOffset(&q);
75
76 // Set primal warm start
77 std::vector<c_float> primal_warm_start;
78 SetPrimalWarmStart(&primal_warm_start);
79
80 OSQPData* data = reinterpret_cast<OSQPData*>(c_malloc(sizeof(OSQPData)));
81 OSQPSettings* settings =
82 reinterpret_cast<OSQPSettings*>(c_malloc(sizeof(OSQPSettings)));
83
84 // Define Solver settings
85 osqp_set_default_settings(settings);
86 settings->max_iter = max_iter_;
87 settings->time_limit = time_limit_;
88 settings->verbose = verbose_;
89 settings->scaled_termination = scaled_termination_;
90 settings->warm_start = warm_start_;
91
92 OSQPWorkspace* work = nullptr;
93
94 bool res = OptimizeWithOsqp(num_of_variables_, lower_bounds.size(), &P_data,
95 &P_indices, &P_indptr, &A_data, &A_indices,
96 &A_indptr, &lower_bounds, &upper_bounds, &q,
97 &primal_warm_start, data, &work, settings);
98 if (res == false || work == nullptr || work->solution == nullptr) {
99 AERROR << "Failed to find solution.";
100 // Cleanup
101 osqp_cleanup(work);
102 c_free(data->A);
103 c_free(data->P);
104 c_free(data);
105 c_free(settings);
106
107 return false;
108 }
109
110 // Extract primal results
111 x_.resize(num_of_points_);
112 y_.resize(num_of_points_);
113 for (int i = 0; i < num_of_points_; ++i) {
114 int index = i * 2;
115 x_.at(i) = work->solution->x[index];
116 y_.at(i) = work->solution->x[index + 1];
117 }
118
119 // Cleanup
120 osqp_cleanup(work);
121 c_free(data->A);
122 c_free(data->P);
123 c_free(data);
124 c_free(settings);
125
126 return true;
127}
128
129void FemPosDeviationOsqpInterface::CalculateKernel(
130 std::vector<c_float>* P_data, std::vector<c_int>* P_indices,
131 std::vector<c_int>* P_indptr) {
132 CHECK_GT(num_of_variables_, 4);
133
134 // Three quadratic penalties are involved:
135 // 1. Penalty x on distance between middle point and point by finite element
136 // estimate;
137 // 2. Penalty y on path length;
138 // 3. Penalty z on difference between points and reference points
139
140 // General formulation of P matrix is as below(with 6 points as an example):
141 // I is a two by two identity matrix, X, Y, Z represents x * I, y * I, z * I
142 // 0 is a two by two zero matrix
143 // |X+Y+Z, -2X-Y, X, 0, 0, 0 |
144 // |0, 5X+2Y+Z, -4X-Y, X, 0, 0 |
145 // |0, 0, 6X+2Y+Z, -4X-Y, X, 0 |
146 // |0, 0, 0, 6X+2Y+Z, -4X-Y, X |
147 // |0, 0, 0, 0, 5X+2Y+Z, -2X-Y|
148 // |0, 0, 0, 0, 0, X+Y+Z|
149
150 // Only upper triangle needs to be filled
151 std::vector<std::vector<std::pair<c_int, c_float>>> columns;
152 columns.resize(num_of_variables_);
153 int col_num = 0;
154
155 for (int col = 0; col < 2; ++col) {
156 columns[col].emplace_back(col, weight_fem_pos_deviation_ +
157 weight_path_length_ +
158 weight_ref_deviation_);
159 ++col_num;
160 }
161
162 for (int col = 2; col < 4; ++col) {
163 columns[col].emplace_back(
164 col - 2, -2.0 * weight_fem_pos_deviation_ - weight_path_length_);
165 columns[col].emplace_back(col, 5.0 * weight_fem_pos_deviation_ +
166 2.0 * weight_path_length_ +
167 weight_ref_deviation_);
168 ++col_num;
169 }
170
171 int second_point_from_last_index = num_of_points_ - 2;
172 for (int point_index = 2; point_index < second_point_from_last_index;
173 ++point_index) {
174 int col_index = point_index * 2;
175 for (int col = 0; col < 2; ++col) {
176 col_index += col;
177 columns[col_index].emplace_back(col_index - 4, weight_fem_pos_deviation_);
178 columns[col_index].emplace_back(
179 col_index - 2,
180 -4.0 * weight_fem_pos_deviation_ - weight_path_length_);
181 columns[col_index].emplace_back(
182 col_index, 6.0 * weight_fem_pos_deviation_ +
183 2.0 * weight_path_length_ + weight_ref_deviation_);
184 ++col_num;
185 }
186 }
187
188 int second_point_col_from_last_col = num_of_variables_ - 4;
189 int last_point_col_from_last_col = num_of_variables_ - 2;
190 for (int col = second_point_col_from_last_col;
191 col < last_point_col_from_last_col; ++col) {
192 columns[col].emplace_back(col - 4, weight_fem_pos_deviation_);
193 columns[col].emplace_back(
194 col - 2, -4.0 * weight_fem_pos_deviation_ - weight_path_length_);
195 columns[col].emplace_back(col, 5.0 * weight_fem_pos_deviation_ +
196 2.0 * weight_path_length_ +
197 weight_ref_deviation_);
198 ++col_num;
199 }
200
201 for (int col = last_point_col_from_last_col; col < num_of_variables_; ++col) {
202 columns[col].emplace_back(col - 4, weight_fem_pos_deviation_);
203 columns[col].emplace_back(
204 col - 2, -2.0 * weight_fem_pos_deviation_ - weight_path_length_);
205 columns[col].emplace_back(col, weight_fem_pos_deviation_ +
206 weight_path_length_ +
207 weight_ref_deviation_);
208 ++col_num;
209 }
210
211 CHECK_EQ(col_num, num_of_variables_);
212
213 int ind_p = 0;
214 for (int i = 0; i < col_num; ++i) {
215 P_indptr->push_back(ind_p);
216 for (const auto& row_data_pair : columns[i]) {
217 // Rescale by 2.0 as the quadratic term in osqp default qp problem setup
218 // is set as (1/2) * x' * P * x
219 P_data->push_back(row_data_pair.second * 2.0);
220 P_indices->push_back(row_data_pair.first);
221 ++ind_p;
222 }
223 }
224 P_indptr->push_back(ind_p);
225}
226
227void FemPosDeviationOsqpInterface::CalculateOffset(std::vector<c_float>* q) {
228 for (int i = 0; i < num_of_points_; ++i) {
229 const auto& ref_point_xy = ref_points_[i];
230 q->push_back(-2.0 * weight_ref_deviation_ * ref_point_xy.first);
231 q->push_back(-2.0 * weight_ref_deviation_ * ref_point_xy.second);
232 }
233}
234
235void FemPosDeviationOsqpInterface::CalculateAffineConstraint(
236 std::vector<c_float>* A_data, std::vector<c_int>* A_indices,
237 std::vector<c_int>* A_indptr, std::vector<c_float>* lower_bounds,
238 std::vector<c_float>* upper_bounds) {
239 int ind_A = 0;
240 for (int i = 0; i < num_of_variables_; ++i) {
241 A_data->push_back(1.0);
242 A_indices->push_back(i);
243 A_indptr->push_back(ind_A);
244 ++ind_A;
245 }
246 A_indptr->push_back(ind_A);
247
248 for (int i = 0; i < num_of_points_; ++i) {
249 const auto& ref_point_xy = ref_points_[i];
250 upper_bounds->push_back(ref_point_xy.first + bounds_around_refs_[i]);
251 upper_bounds->push_back(ref_point_xy.second + bounds_around_refs_[i]);
252 lower_bounds->push_back(ref_point_xy.first - bounds_around_refs_[i]);
253 lower_bounds->push_back(ref_point_xy.second - bounds_around_refs_[i]);
254 }
255}
256
257void FemPosDeviationOsqpInterface::SetPrimalWarmStart(
258 std::vector<c_float>* primal_warm_start) {
259 CHECK_EQ(ref_points_.size(), static_cast<size_t>(num_of_points_));
260 for (const auto& ref_point_xy : ref_points_) {
261 primal_warm_start->push_back(ref_point_xy.first);
262 primal_warm_start->push_back(ref_point_xy.second);
263 }
264}
265
266bool FemPosDeviationOsqpInterface::OptimizeWithOsqp(
267 const size_t kernel_dim, const size_t num_affine_constraint,
268 std::vector<c_float>* P_data, std::vector<c_int>* P_indices,
269 std::vector<c_int>* P_indptr, std::vector<c_float>* A_data,
270 std::vector<c_int>* A_indices, std::vector<c_int>* A_indptr,
271 std::vector<c_float>* lower_bounds, std::vector<c_float>* upper_bounds,
272 std::vector<c_float>* q, std::vector<c_float>* primal_warm_start,
273 OSQPData* data, OSQPWorkspace** work, OSQPSettings* settings) {
274 CHECK_EQ(lower_bounds->size(), upper_bounds->size());
275
276 data->n = kernel_dim;
277 data->m = num_affine_constraint;
278 data->P = csc_matrix(data->n, data->n, P_data->size(), P_data->data(),
279 P_indices->data(), P_indptr->data());
280 data->q = q->data();
281 data->A = csc_matrix(data->m, data->n, A_data->size(), A_data->data(),
282 A_indices->data(), A_indptr->data());
283 data->l = lower_bounds->data();
284 data->u = upper_bounds->data();
285
286 *work = osqp_setup(data, settings);
287 // osqp_setup(work, data, settings);
288
289 osqp_warm_start_x(*work, primal_warm_start->data());
290
291 // Solve Problem
292 osqp_solve(*work);
293
294 auto status = (*work)->info->status_val;
295
296 if (status < 0) {
297 AERROR << "failed optimization status:\t" << (*work)->info->status;
298 return false;
299 }
300
301 if (status != 1 && status != 2) {
302 AERROR << "failed optimization status:\t" << (*work)->info->status;
303 return false;
304 }
305
306 return true;
307}
308
309} // namespace planning
310} // namespace apollo
Planning module main class.
#define AERROR
Definition log.h:44
class register implement
Definition arena_queue.h:37