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),
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),
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_;
53void MpcOsqp::CalculateKernel(std::vector<c_float> *P_data,
54 std::vector<c_int> *P_indices,
55 std::vector<c_int> *P_indptr) {
57 std::vector<std::vector<std::pair<c_int, c_float>>> columns;
58 columns.resize(num_param_);
59 size_t value_index = 0;
61 for (
size_t i = 0; i <= horizon_; ++i) {
62 for (
size_t j = 0; j < state_dim_; ++j) {
64 columns[i * state_dim_ + j].emplace_back(i * state_dim_ + j,
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) {
74 columns[i * control_dim_ + j + state_total_dim].emplace_back(
75 state_total_dim + i * control_dim_ + j, matrix_r_(j, j));
79 CHECK_EQ(value_index, num_param_);
82 for (
size_t i = 0; i < num_param_; ++i) {
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);
87 P_indices->emplace_back(row_data_pair.first);
91 P_indptr->emplace_back(ind_p);
95void MpcOsqp::CalculateGradient() {
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_;
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;
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;
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;
127 Eigen::MatrixXd control_identity_mat =
128 Eigen::MatrixXd::Identity(control_dim_, control_dim_);
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_;
134 ADEBUG <<
"matrix_constraint with A";
135 ADEBUG << matrix_constraint;
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_;
142 ADEBUG <<
"matrix_constraint with B";
143 ADEBUG << matrix_constraint;
145 Eigen::MatrixXd all_identity_mat =
146 Eigen::MatrixXd::Identity(num_param_, num_param_);
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;
153 std::vector<std::vector<std::pair<c_int, c_float>>> columns;
154 columns.resize(num_param_ + 1);
157 for (
size_t i = 0; i < num_param_; ++i) {
158 for (
size_t j = 0; j < num_param_ + state_dim_ * (horizon_ + 1);
160 if (std::fabs(matrix_constraint(j, i)) > kEpsilon) {
162 columns[i].emplace_back(j, matrix_constraint(j, i));
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);
173 A_indices->emplace_back(row_data_pair.first);
177 A_indptr->emplace_back(ind_A);
180void MpcOsqp::CalculateConstraintVectors() {
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_;
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_;
197 ADEBUG <<
" matrix_x_lower_";
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_";
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;
219OSQPSettings *MpcOsqp::Settings() {
221 OSQPSettings *settings =
222 reinterpret_cast<OSQPSettings *
>(c_malloc(
sizeof(OSQPSettings)));
223 if (settings ==
nullptr) {
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_;
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) {
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";
253 csc_matrix(kernel_dim, kernel_dim, P_data.size(), CopyData(P_data),
254 CopyData(P_indices), CopyData(P_indptr));
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";
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));
269 data->l = lowerBound_.data();
270 data->u = upperBound_.data();
275void MpcOsqp::FreeData(OSQPData *data) {
282 ADEBUG <<
"Before Calc Gradient";
284 ADEBUG <<
"After Calc Gradient";
285 CalculateConstraintVectors();
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];
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];
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];
304 OSQPSettings *settings = Settings();
305 ADEBUG <<
"OSQP setting done";
306 OSQPWorkspace *osqp_workspace =
nullptr;
308 osqp_workspace = osqp_setup(data, settings);
309 ADEBUG <<
"OSQP workspace ready";
310 osqp_solve(osqp_workspace);
312 auto status = osqp_workspace->info->status_val;
313 ADEBUG <<
"status:" << status;
315 if (status < 0 || (status != 1 && status != 2)) {
316 AERROR <<
"failed optimization status:\t" << osqp_workspace->info->status;
317 osqp_cleanup(osqp_workspace);
321 }
else if (osqp_workspace->solution ==
nullptr) {
322 AERROR <<
"The solution from OSQP is nullptr";
323 osqp_cleanup(osqp_workspace);
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);
336 osqp_cleanup(osqp_workspace);
bool Solve(std::vector< double > *control_cmd)
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.