A sparse MPC solver for walking motion generation (old version).
|
00001 00008 /**************************************** 00009 * INCLUDES 00010 ****************************************/ 00011 #include "qp_ip.h" 00012 #include "state_handling.h" 00013 00014 00015 #include <cmath> // log, fabs 00016 00017 /**************************************** 00018 * FUNCTIONS 00019 ****************************************/ 00020 00021 00022 //============================================== 00023 // qp_ip 00024 00034 qp_ip::qp_ip( 00035 const int N_, 00036 const double Alpha, 00037 const double Beta, 00038 const double Gamma, 00039 const double regularization, 00040 const double tol_) : 00041 qp_solver (N_, Alpha, Beta, Gamma, regularization, tol_), 00042 chol (N_) 00043 { 00044 g = new double[2*N]; 00045 i2hess = new double[2*N]; 00046 i2hess_grad = new double[N*SMPC_NUM_VAR]; 00047 grad = new double[N*SMPC_NUM_VAR]; 00048 00049 Q[0] = Beta/2; 00050 Q[1] = Alpha/2; 00051 Q[2] = regularization; 00052 P = Gamma/2; 00053 } 00054 00055 00057 qp_ip::~qp_ip() 00058 { 00059 if (g != NULL) 00060 delete g; 00061 if (i2hess != NULL) 00062 delete i2hess; 00063 if (i2hess_grad != NULL) 00064 delete i2hess_grad; 00065 if (grad != NULL) 00066 delete grad; 00067 } 00068 00069 00081 void qp_ip::set_parameters( 00082 const double* T, 00083 const double* h, 00084 const double h_initial_, 00085 const double* angle, 00086 const double* zref_x, 00087 const double* zref_y, 00088 const double* lb_, 00089 const double* ub_) 00090 { 00091 h_initial = h_initial_; 00092 set_state_parameters (T, h, h_initial_, angle); 00093 00094 lb = lb_; 00095 ub = ub_; 00096 00097 form_g (zref_x, zref_y); 00098 } 00099 00100 00101 00108 void qp_ip::form_g (const double *zref_x, const double *zref_y) 00109 { 00110 double p0, p1; 00111 double cosA, sinA; 00112 00113 for (int i = 0; i < N; i++) 00114 { 00115 cosA = spar[i].cos; 00116 sinA = spar[i].sin; 00117 00118 // zref 00119 p0 = zref_x[i]; 00120 p1 = zref_y[i]; 00121 00122 // inv (2*H) * R' * Cp' * zref 00123 g[i*2] = -(cosA*p0 + sinA*p1)*gain_beta; 00124 g[i*2 + 1] = -(-sinA*p0 + cosA*p1)*gain_beta; 00125 } 00126 } 00127 00128 00129 00136 void qp_ip::form_grad_i2hess_logbar (const double kappa) 00137 { 00138 phi_X = 0; 00139 int i,j; 00140 00141 00142 // grad = H*X + g + kappa * b; 00143 // initialize grad = H*X 00144 for (i = 0; i < N*SMPC_NUM_STATE_VAR; i++) 00145 { 00146 grad[i] = X[i] / i2Q[i%3]; 00147 } 00148 for (; i < N*SMPC_NUM_VAR; i++) 00149 { 00150 grad[i] = X[i] / i2P; 00151 } 00152 00153 // finish initalization of grad 00154 // initialize inverted hessian 00155 // initialize logarithmic barrier in the function 00156 for (i = 0, j = 0; i < 2*N; i++, j += 3) 00157 { 00158 double lb_diff = -lb[i] + X[j]; 00159 double ub_diff = ub[i] - X[j]; 00160 00161 // logarithmic barrier 00162 phi_X -= log(lb_diff) + log(ub_diff); 00163 00164 lb_diff = 1/lb_diff; 00165 ub_diff = 1/ub_diff; 00166 00167 // grad += g + kappa * (ub_diff - lb_diff) 00168 grad[j] += g[i] + kappa * (ub_diff - lb_diff); 00169 00170 // only elements 1:3:N*SMPC_NUM_STATE_VAR on the diagonal of hessian 00171 // can change 00172 // hess = H + kappa * (ub_diff^2 - lb_diff^2) 00173 i2hess[i] = 1/(2*Q[0] + kappa * (ub_diff*ub_diff + lb_diff*lb_diff)); 00174 } 00175 phi_X *= kappa; 00176 } 00177 00178 00179 00183 void qp_ip::form_i2hess_grad () 00184 { 00185 int i,j; 00186 for (i = 0, j = 0; i < N*2; i++) 00187 { 00188 i2hess_grad[j] = - grad[j] * i2hess[i]; 00189 j++; 00190 i2hess_grad[j] = - grad[j] * i2Q[1]; 00191 j++; 00192 i2hess_grad[j] = - grad[j] * i2Q[2]; 00193 j++; 00194 } 00195 for (i = N*SMPC_NUM_STATE_VAR; i < N*SMPC_NUM_VAR; i++) 00196 { 00197 i2hess_grad[i] = - grad[i] * i2P; 00198 } 00199 } 00200 00201 00202 00207 void qp_ip::form_phi_X () 00208 { 00209 int i; 00210 00211 // phi_X += X'*H*X 00212 for (i = 0; i < N*SMPC_NUM_STATE_VAR; i++) 00213 { 00214 phi_X += Q[i%3] * X[i] * X[i]; 00215 } 00216 for (; i < N*SMPC_NUM_VAR; i++) 00217 { 00218 phi_X += P * X[i] * X[i]; 00219 } 00220 00221 // phi_X += g'*X 00222 for (i = 0; i < 2*N; i++) 00223 { 00224 phi_X += g[i] * X[i*3]; 00225 } 00226 } 00227 00228 00234 void qp_ip::init_alpha() 00235 { 00236 double min_alpha = 1; 00237 alpha = 1; 00238 00239 for (int i = 0; i < 2*N; i++) 00240 { 00241 // lower bound may be violated 00242 if (dX[i*3] < 0) 00243 { 00244 double tmp_alpha = (lb[i]-X[i*3])/dX[i*3]; 00245 if (tmp_alpha < min_alpha) 00246 { 00247 min_alpha = tmp_alpha; 00248 } 00249 } 00250 // upper bound may be violated 00251 else if (dX[i*3] > 0) 00252 { 00253 double tmp_alpha = (ub[i]-X[i*3])/dX[i*3]; 00254 if (tmp_alpha < min_alpha) 00255 { 00256 min_alpha = tmp_alpha; 00257 } 00258 } 00259 } 00260 00261 if (min_alpha > tol) 00262 { 00263 while (alpha > min_alpha) 00264 { 00265 alpha *= bs_beta; 00266 } 00267 } 00268 else 00269 { 00270 alpha = 0; 00271 } 00272 } 00273 00274 00275 00281 double qp_ip::form_bs_alpha_grad_dX () 00282 { 00283 double res = 0; 00284 00285 for (int i = 0; i < N*SMPC_NUM_VAR; i++) 00286 { 00287 res += grad[i]*dX[i]; 00288 } 00289 00290 return (res*bs_alpha); 00291 } 00292 00293 00301 double qp_ip::form_phi_X_tmp (const double kappa) 00302 { 00303 int i,j; 00304 double res = 0; 00305 double X_tmp; 00306 00307 00308 // phi_X += X'*H*X 00309 for (i = 0,j = 0; i < 2*N; i++) 00310 { 00311 X_tmp = X[j] + alpha * dX[j]; 00312 j++; 00313 00314 // logarithmic barrier 00315 res -= kappa * (log(-lb[i] + X_tmp) + log(ub[i] - X_tmp)); 00316 00317 // phi_X += g'*X 00318 res += g[i] * X_tmp; 00319 00320 00321 // phi_X += X'*H*X // states 00322 res += Q[0] * X_tmp*X_tmp; 00323 00324 X_tmp = X[j] + alpha * dX[j]; 00325 j++; 00326 res += Q[1] * X_tmp*X_tmp; 00327 00328 X_tmp = X[j] + alpha * dX[j]; 00329 j++; 00330 res += Q[2] * X_tmp*X_tmp; 00331 } 00332 // phi_X += X'*H*X // controls 00333 for (i = N*SMPC_NUM_STATE_VAR; i < N*SMPC_NUM_VAR; i++) 00334 { 00335 X_tmp = X[i] + alpha * dX[i]; 00336 res += P * X_tmp * X_tmp; 00337 } 00338 00339 return (res); 00340 } 00341 00342 00343 00354 void qp_ip::set_ip_parameters ( 00355 const double t_, 00356 const double mu_, 00357 const double bs_alpha_, 00358 const double bs_beta_, 00359 const int max_iter_, 00360 const double tol_out_) 00361 { 00362 t = t_; 00363 mu = mu_; 00364 bs_alpha = bs_alpha_; 00365 bs_beta = bs_beta_; 00366 max_iter = max_iter_; 00367 tol_out = tol_out_; 00368 } 00369 00370 00371 00377 int qp_ip::solve() 00378 { 00379 double kappa = 1/t; 00380 double duality_gap = 2*N*kappa; 00381 int i; 00382 00383 00384 while (duality_gap > tol_out) 00385 { 00386 for (i = 0; (i < max_iter) && solve_onestep(kappa); i++); 00387 if (i == max_iter) 00388 { 00389 return (-1); 00390 } 00391 00392 kappa /= mu; 00393 duality_gap = 2*N*kappa; 00394 } 00395 return (0); 00396 } 00397 00398 00406 bool qp_ip::solve_onestep (const double kappa) 00407 { 00408 int i,j; 00409 00410 00411 form_grad_i2hess_logbar (kappa); 00412 form_phi_X (); 00413 form_i2hess_grad (); 00414 00415 chol.solve (*this, i2hess_grad, i2hess, X, dX); 00416 00417 00418 // stopping criterion (decrement) 00419 double decrement = 0; 00420 for (i = 0, j = 0; i < N*2; i++) 00421 { 00422 decrement += dX[j] * dX[j] / i2hess[i]; 00423 j++; 00424 decrement += dX[j] * dX[j] / i2Q[1]; 00425 j++; 00426 decrement += dX[j] * dX[j] / i2Q[2]; 00427 j++; 00428 } 00429 for (i = N*SMPC_NUM_STATE_VAR; i < N*SMPC_NUM_VAR; i++) 00430 { 00431 decrement += dX[i] * dX[i] / i2P; 00432 } 00433 if (decrement < tol) 00434 { 00435 return (false); 00436 } 00437 00438 00439 init_alpha (); 00440 // stopping criterion (step size) 00441 if (alpha < tol) 00442 { 00443 return (false); // done 00444 } 00445 00446 00447 // backtracking search 00448 double bs_alpha_grad_dX = form_bs_alpha_grad_dX (); 00449 for (;;) 00450 { 00451 if (form_phi_X_tmp (kappa) <= phi_X + alpha * bs_alpha_grad_dX) 00452 { 00453 break; 00454 } 00455 00456 alpha = bs_beta * alpha; 00457 00458 // stopping criterion (step size) 00459 if (alpha < tol) 00460 { 00461 return (false); // done 00462 } 00463 } 00464 00465 00466 // Move in the feasible descent direction 00467 for (j = 0; j < N*SMPC_NUM_VAR ; j++) 00468 { 00469 X[j] += alpha * dX[j]; 00470 } 00471 00472 return (true); 00473 }