Apollo 10.0
自动驾驶开放平台
mpc_osqp.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
18
19namespace apollo {
20namespace common {
21namespace math {
22MpcOsqp::MpcOsqp(const Eigen::MatrixXd &matrix_a,
23 const Eigen::MatrixXd &matrix_b,
24 const Eigen::MatrixXd &matrix_q,
25 const Eigen::MatrixXd &matrix_r,
26 const Eigen::MatrixXd &matrix_initial_x,
27 const Eigen::MatrixXd &matrix_u_lower,
28 const Eigen::MatrixXd &matrix_u_upper,
29 const Eigen::MatrixXd &matrix_x_lower,
30 const Eigen::MatrixXd &matrix_x_upper,
31 const Eigen::MatrixXd &matrix_x_ref, const int max_iter,
32 const int horizon, const double eps_abs)
33 : matrix_a_(matrix_a),
34 matrix_b_(matrix_b),
35 matrix_q_(matrix_q),
36 matrix_r_(matrix_r),
37 matrix_initial_x_(matrix_initial_x),
38 matrix_u_lower_(matrix_u_lower),
39 matrix_u_upper_(matrix_u_upper),
40 matrix_x_lower_(matrix_x_lower),
41 matrix_x_upper_(matrix_x_upper),
42 matrix_x_ref_(matrix_x_ref),
43 max_iteration_(max_iter),
44 horizon_(horizon),
45 eps_abs_(eps_abs) {
46 state_dim_ = matrix_b.rows();
47 control_dim_ = matrix_b.cols();
48 ADEBUG << "state_dim" << state_dim_;
49 ADEBUG << "control_dim_" << control_dim_;
50 num_param_ = state_dim_ * (horizon_ + 1) + control_dim_ * horizon_;
51}
52
53void MpcOsqp::CalculateKernel(std::vector<c_float> *P_data,
54 std::vector<c_int> *P_indices,
55 std::vector<c_int> *P_indptr) {
56 // col1:(row,val),...; col2:(row,val),....; ...
57 std::vector<std::vector<std::pair<c_int, c_float>>> columns;
58 columns.resize(num_param_);
59 size_t value_index = 0;
60 // state and terminal state
61 for (size_t i = 0; i <= horizon_; ++i) {
62 for (size_t j = 0; j < state_dim_; ++j) {
63 // (row, val)
64 columns[i * state_dim_ + j].emplace_back(i * state_dim_ + j,
65 matrix_q_(j, j));
66 ++value_index;
67 }
68 }
69 // control
70 const size_t state_total_dim = state_dim_ * (horizon_ + 1);
71 for (size_t i = 0; i < horizon_; ++i) {
72 for (size_t j = 0; j < control_dim_; ++j) {
73 // (row, val)
74 columns[i * control_dim_ + j + state_total_dim].emplace_back(
75 state_total_dim + i * control_dim_ + j, matrix_r_(j, j));
76 ++value_index;
77 }
78 }
79 CHECK_EQ(value_index, num_param_);
80
81 int ind_p = 0;
82 for (size_t i = 0; i < num_param_; ++i) {
83 // TODO(SHU) Check this
84 P_indptr->emplace_back(ind_p);
85 for (const auto &row_data_pair : columns[i]) {
86 P_data->emplace_back(row_data_pair.second); // val
87 P_indices->emplace_back(row_data_pair.first); // row
88 ++ind_p;
89 }
90 }
91 P_indptr->emplace_back(ind_p);
92}
93
94// reference is always zero
95void MpcOsqp::CalculateGradient() {
96 // populate the gradient vector
97 gradient_ = Eigen::VectorXd::Zero(
98 state_dim_ * (horizon_ + 1) + control_dim_ * horizon_, 1);
99 for (size_t i = 0; i < horizon_ + 1; i++) {
100 gradient_.block(i * state_dim_, 0, state_dim_, 1) =
101 -1.0 * matrix_q_ * matrix_x_ref_;
102 }
103 ADEBUG << "Gradient_mat";
104 ADEBUG << gradient_;
105}
106
107// equality constraints x(k+1) = A*x(k)
108void MpcOsqp::CalculateEqualityConstraint(std::vector<c_float> *A_data,
109 std::vector<c_int> *A_indices,
110 std::vector<c_int> *A_indptr) {
111 static constexpr double kEpsilon = 1e-6;
112 // block matrix
113 Eigen::MatrixXd matrix_constraint = Eigen::MatrixXd::Zero(
114 state_dim_ * (horizon_ + 1) + state_dim_ * (horizon_ + 1) +
115 control_dim_ * horizon_,
116 state_dim_ * (horizon_ + 1) + control_dim_ * horizon_);
117 Eigen::MatrixXd state_identity_mat = Eigen::MatrixXd::Identity(
118 state_dim_ * (horizon_ + 1), state_dim_ * (horizon_ + 1));
119 ADEBUG << "state_identity_mat" << state_identity_mat;
120
121 matrix_constraint.block(0, 0, state_dim_ * (horizon_ + 1),
122 state_dim_ * (horizon_ + 1)) =
123 -1 * state_identity_mat;
124 ADEBUG << "matrix_constraint";
125 ADEBUG << matrix_constraint;
126
127 Eigen::MatrixXd control_identity_mat =
128 Eigen::MatrixXd::Identity(control_dim_, control_dim_);
129
130 for (size_t i = 0; i < horizon_; i++) {
131 matrix_constraint.block((i + 1) * state_dim_, i * state_dim_, state_dim_,
132 state_dim_) = matrix_a_;
133 }
134 ADEBUG << "matrix_constraint with A";
135 ADEBUG << matrix_constraint;
136
137 for (size_t i = 0; i < horizon_; i++) {
138 matrix_constraint.block((i + 1) * state_dim_,
139 i * control_dim_ + (horizon_ + 1) * state_dim_,
140 state_dim_, control_dim_) = matrix_b_;
141 }
142 ADEBUG << "matrix_constraint with B";
143 ADEBUG << matrix_constraint;
144
145 Eigen::MatrixXd all_identity_mat =
146 Eigen::MatrixXd::Identity(num_param_, num_param_);
147
148 matrix_constraint.block(state_dim_ * (horizon_ + 1), 0, num_param_,
149 num_param_) = all_identity_mat;
150 ADEBUG << "matrix_constraint with I";
151 ADEBUG << matrix_constraint;
152
153 std::vector<std::vector<std::pair<c_int, c_float>>> columns;
154 columns.resize(num_param_ + 1);
155 int value_index = 0;
156 // state and terminal state
157 for (size_t i = 0; i < num_param_; ++i) { // col
158 for (size_t j = 0; j < num_param_ + state_dim_ * (horizon_ + 1);
159 ++j) // row
160 if (std::fabs(matrix_constraint(j, i)) > kEpsilon) {
161 // (row, val)
162 columns[i].emplace_back(j, matrix_constraint(j, i));
163 ++value_index;
164 }
165 }
166 ADEBUG << "value_index";
167 ADEBUG << value_index;
168 int ind_A = 0;
169 for (size_t i = 0; i < num_param_; ++i) {
170 A_indptr->emplace_back(ind_A);
171 for (const auto &row_data_pair : columns[i]) {
172 A_data->emplace_back(row_data_pair.second); // value
173 A_indices->emplace_back(row_data_pair.first); // row
174 ++ind_A;
175 }
176 }
177 A_indptr->emplace_back(ind_A);
178}
179
180void MpcOsqp::CalculateConstraintVectors() {
181 // evaluate the lower and the upper inequality vectors
182 Eigen::VectorXd lowerInequality = Eigen::MatrixXd::Zero(
183 state_dim_ * (horizon_ + 1) + control_dim_ * horizon_, 1);
184 Eigen::VectorXd upperInequality = Eigen::MatrixXd::Zero(
185 state_dim_ * (horizon_ + 1) + control_dim_ * horizon_, 1);
186 for (size_t i = 0; i < horizon_; i++) {
187 lowerInequality.block(control_dim_ * i + state_dim_ * (horizon_ + 1), 0,
188 control_dim_, 1) = matrix_u_lower_;
189 upperInequality.block(control_dim_ * i + state_dim_ * (horizon_ + 1), 0,
190 control_dim_, 1) = matrix_u_upper_;
191 }
192 ADEBUG << " matrix_u_lower_";
193 for (size_t i = 0; i < horizon_ + 1; i++) {
194 lowerInequality.block(state_dim_ * i, 0, state_dim_, 1) = matrix_x_lower_;
195 upperInequality.block(state_dim_ * i, 0, state_dim_, 1) = matrix_x_upper_;
196 }
197 ADEBUG << " matrix_x_lower_";
198
199 // evaluate the lower and the upper equality vectors
200 Eigen::VectorXd lowerEquality =
201 Eigen::MatrixXd::Zero(state_dim_ * (horizon_ + 1), 1);
202 Eigen::VectorXd upperEquality;
203 lowerEquality.block(0, 0, state_dim_, 1) = -1 * matrix_initial_x_;
204 upperEquality = lowerEquality;
205 lowerEquality = lowerEquality;
206 ADEBUG << " matrix_initial_x_";
207
208 // merge inequality and equality vectors
209 lowerBound_ = Eigen::MatrixXd::Zero(
210 2 * state_dim_ * (horizon_ + 1) + control_dim_ * horizon_, 1);
211 lowerBound_ << lowerEquality, lowerInequality;
212 ADEBUG << " lowerBound_ ";
213 upperBound_ = Eigen::MatrixXd::Zero(
214 2 * state_dim_ * (horizon_ + 1) + control_dim_ * horizon_, 1);
215 upperBound_ << upperEquality, upperInequality;
216 ADEBUG << " upperBound_";
217}
218
219OSQPSettings *MpcOsqp::Settings() {
220 // default setting
221 OSQPSettings *settings =
222 reinterpret_cast<OSQPSettings *>(c_malloc(sizeof(OSQPSettings)));
223 if (settings == nullptr) {
224 return nullptr;
225 } else {
226 osqp_set_default_settings(settings);
227 settings->polish = true;
228 settings->scaled_termination = true;
229 settings->verbose = false;
230 settings->max_iter = max_iteration_;
231 settings->eps_abs = eps_abs_;
232 return settings;
233 }
234}
235
236OSQPData *MpcOsqp::Data() {
237 OSQPData *data = reinterpret_cast<OSQPData *>(c_malloc(sizeof(OSQPData)));
238 size_t kernel_dim = state_dim_ * (horizon_ + 1) + control_dim_ * horizon_;
239 size_t num_affine_constraint =
240 2 * state_dim_ * (horizon_ + 1) + control_dim_ * horizon_;
241 if (data == nullptr) {
242 return nullptr;
243 } else {
244 data->n = kernel_dim;
245 data->m = num_affine_constraint;
246 std::vector<c_float> P_data;
247 std::vector<c_int> P_indices;
248 std::vector<c_int> P_indptr;
249 ADEBUG << "before CalculateKernel";
250 CalculateKernel(&P_data, &P_indices, &P_indptr);
251 ADEBUG << "CalculateKernel done";
252 data->P =
253 csc_matrix(kernel_dim, kernel_dim, P_data.size(), CopyData(P_data),
254 CopyData(P_indices), CopyData(P_indptr));
255 ADEBUG << "Get P matrix";
256 data->q = gradient_.data();
257 ADEBUG << "before CalculateEqualityConstraint";
258 std::vector<c_float> A_data;
259 std::vector<c_int> A_indices;
260 std::vector<c_int> A_indptr;
261 CalculateEqualityConstraint(&A_data, &A_indices, &A_indptr);
262 ADEBUG << "CalculateEqualityConstraint done";
263 data->A =
264 csc_matrix(state_dim_ * (horizon_ + 1) + state_dim_ * (horizon_ + 1) +
265 control_dim_ * horizon_,
266 kernel_dim, A_data.size(), CopyData(A_data),
267 CopyData(A_indices), CopyData(A_indptr));
268 ADEBUG << "Get A matrix";
269 data->l = lowerBound_.data();
270 data->u = upperBound_.data();
271 return data;
272 }
273}
274
275void MpcOsqp::FreeData(OSQPData *data) {
276 c_free(data->A);
277 c_free(data->P);
278 c_free(data);
279}
280
281bool MpcOsqp::Solve(std::vector<double> *control_cmd) {
282 ADEBUG << "Before Calc Gradient";
283 CalculateGradient();
284 ADEBUG << "After Calc Gradient";
285 CalculateConstraintVectors();
286 ADEBUG << "MPC2Matrix";
287
288 OSQPData *data = Data();
289 ADEBUG << "OSQP data done";
290 ADEBUG << "OSQP data n" << data->n;
291 ADEBUG << "OSQP data m" << data->m;
292 for (int i = 0; i < data->n; ++i) {
293 ADEBUG << "OSQP data q" << i << ":" << (data->q)[i];
294 }
295 ADEBUG << "OSQP data l" << data->l;
296 for (int i = 0; i < data->m; ++i) {
297 ADEBUG << "OSQP data l" << i << ":" << (data->l)[i];
298 }
299 ADEBUG << "OSQP data u" << data->u;
300 for (int i = 0; i < data->m; ++i) {
301 ADEBUG << "OSQP data u" << i << ":" << (data->u)[i];
302 }
303
304 OSQPSettings *settings = Settings();
305 ADEBUG << "OSQP setting done";
306 OSQPWorkspace *osqp_workspace = nullptr;
307 // osqp_setup(&osqp_workspace, data, settings);
308 osqp_workspace = osqp_setup(data, settings);
309 ADEBUG << "OSQP workspace ready";
310 osqp_solve(osqp_workspace);
311
312 auto status = osqp_workspace->info->status_val;
313 ADEBUG << "status:" << status;
314 // check status
315 if (status < 0 || (status != 1 && status != 2)) {
316 AERROR << "failed optimization status:\t" << osqp_workspace->info->status;
317 osqp_cleanup(osqp_workspace);
318 FreeData(data);
319 c_free(settings);
320 return false;
321 } else if (osqp_workspace->solution == nullptr) {
322 AERROR << "The solution from OSQP is nullptr";
323 osqp_cleanup(osqp_workspace);
324 FreeData(data);
325 c_free(settings);
326 return false;
327 }
328
329 size_t first_control = state_dim_ * (horizon_ + 1);
330 for (size_t i = 0; i < control_dim_; ++i) {
331 control_cmd->at(i) = osqp_workspace->solution->x[i + first_control];
332 ADEBUG << "control_cmd:" << i << ":" << control_cmd->at(i);
333 }
334
335 // Cleanup
336 osqp_cleanup(osqp_workspace);
337 FreeData(data);
338 c_free(settings);
339 return true;
340}
341
342} // namespace math
343} // namespace common
344} // namespace apollo
bool Solve(std::vector< double > *control_cmd)
Definition mpc_osqp.cc:281
MpcOsqp(const Eigen::MatrixXd &matrix_a, const Eigen::MatrixXd &matrix_b, const Eigen::MatrixXd &matrix_q, const Eigen::MatrixXd &matrix_r, const Eigen::MatrixXd &matrix_initial_x, const Eigen::MatrixXd &matrix_u_lower, const Eigen::MatrixXd &matrix_u_upper, const Eigen::MatrixXd &matrix_x_lower, const Eigen::MatrixXd &matrix_x_upper, const Eigen::MatrixXd &matrix_x_ref, const int max_iter, const int horizon, const double eps_abs)
Solver for discrete-time model predictive control problem.
Definition mpc_osqp.cc:22
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
class register implement
Definition arena_queue.h:37