20 #include <yarp/math/Math.h> 21 #include <iCub/ctrl/math.h> 25 #include <IpIpoptApplication.hpp> 35 class HandIK_NLP :
public Ipopt::TNLP
38 HandIK_Problem &problem;
39 HandIK_Variables guess;
40 HandIK_Variables solution;
42 Vector rpy,rpy_offs,encoders;
43 Matrix Hc,thumbH,indexH,middleH;
44 Matrix thumbH_deg0,thumbH_deg1,thumbH_deg2;
45 Matrix Hc_thumbH_deg0,Hc_thumbH_deg1,Hc_thumbH_deg2;
46 Vector thumbH_col2,thumbH_col3;
47 Vector indexH_col2,indexH_col3;
48 Vector middleH_col2,middleH_col3;
50 Matrix dHc_dx0,dHc_dx1,dHc_dx2;
51 Matrix dHc_dx3,dHc_dx4,dHc_dx5;
56 void computeQuantities(
const Ipopt::Number *x)
58 rpy[0]=x[3]+rpy_offs[0];
59 rpy[1]=x[4]+rpy_offs[1];
60 rpy[2]=x[5]+rpy_offs[2];
74 problem.thumb.getChainJoints(encoders,joints);
75 thumbH=problem.thumb.getH(joints);
76 thumbH_col2=thumbH.getCol(2);
77 thumbH_col3=thumbH.getCol(3);
78 thumbH_deg0=problem.thumb.getH(0,
true);
79 thumbH_deg1=problem.thumb.getH(2,
true);
80 thumbH_deg2=problem.thumb.getH(3,
true);
82 Hc_thumbH_deg0=Hc*thumbH_deg0;
83 Hc_thumbH_deg1=Hc*thumbH_deg1;
84 Hc_thumbH_deg2=Hc*thumbH_deg2;
86 problem.index.getChainJoints(encoders,joints);
87 indexH=problem.index.getH(joints);
88 indexH_col2=indexH.getCol(2);
89 indexH_col3=indexH.getCol(3);
91 if (problem.nFingers==3)
96 problem.middle.getChainJoints(encoders,joints);
97 middleH=problem.middle.getH(joints);
98 middleH_col2=middleH.getCol(2);
99 middleH_col3=middleH.getCol(3);
102 double cr=cos(rpy[0]);
double sr=sin(rpy[0]);
103 double cp=cos(rpy[1]);
double sp=sin(rpy[1]);
104 double cy=cos(rpy[2]);
double sy=sin(rpy[2]);
106 Rz(0,0)=cy; Rz(1,1)=cy; Rz(0,1)=-sy; Rz(1,0)=sy;
107 Ry(0,0)=cp; Ry(2,2)=cp; Ry(0,2)=-sp; Ry(2,0)=sp;
108 Rx(1,1)=cr; Rx(2,2)=cr; Rx(1,2)=-sr; Rx(2,1)=sr;
111 dRx(1,1)=-sr; dRx(2,2)=-sr; dRx(1,2)=-cr; dRx(2,1)=cr;
115 dRy(0,0)=-sp; dRy(2,2)=-sp; dRy(0,2)=-cp; dRy(2,0)=cp;
119 dRz(0,0)=-sy; dRz(1,1)=-sy; dRz(0,1)=-cy; dRz(1,0)=cy;
125 HandIK_NLP(HandIK_Problem &p) : problem(p), solution(p.nFingers)
127 encoders.resize(9,0.0);
130 dHc_dx0=zeros(4,4); dHc_dx0(0,3)=1.0;
131 dHc_dx1=zeros(4,4); dHc_dx1(1,3)=1.0;
132 dHc_dx2=zeros(4,4); dHc_dx2(2,3)=1.0;
135 dRz=dRy=dRx=zeros(4,4);
142 rpy_offs.resize(3,0.0);
143 if (problem.hand==
"right")
147 rpy_offs[2]=M_PI/2.0;
158 virtual void setInitialGuess(
const HandIK_Variables &g)
164 virtual HandIK_Variables getSolution()
const 170 bool get_nlp_info(Ipopt::Index &n, Ipopt::Index &m, Ipopt::Index &nnz_jac_g,
171 Ipopt::Index &nnz_h_lag, IndexStyleEnum &index_style)
178 if (problem.nFingers==3)
184 index_style=TNLP::C_STYLE;
190 bool get_bounds_info(Ipopt::Index n, Ipopt::Number *x_l, Ipopt::Number *x_u,
191 Ipopt::Index m, Ipopt::Number *g_l, Ipopt::Number *g_u)
194 Vector zeros(9,0.0),joints;
195 problem.middle.getChainJoints(zeros,joints);
196 double d=1.5*norm(problem.middle.EndEffPosition(joints));
199 if (problem.hand==
"right")
201 x_l[0]=0.0; x_u[0]=problem.dimensions[0]+d;
205 x_l[0]=-problem.dimensions[0]-d; x_u[0]=0.0;
207 x_l[1]=-problem.dimensions[1]-d; x_u[1]=0.0;
208 x_l[2]=0.0; x_u[2]=problem.dimensions[2]+d;
211 if (problem.hand==
"right")
213 x_l[3+0]=0.0; x_u[3+0]=M_PI/2.0;
214 x_l[3+1]=-M_PI/2.0; x_u[3+1]=0.0;
215 x_l[3+2]=-M_PI/2.0; x_u[3+2]=M_PI/2.0;
219 x_l[3+0]=-M_PI/2.0; x_u[3+0]=0.0;
220 x_l[3+1]=-M_PI/2.0; x_u[3+1]=0.0;
221 x_l[3+2]=-M_PI/2.0; x_u[3+2]=M_PI/2.0;
225 iKinChain *chain=problem.thumb.asChain();
226 x_l[6+0]=(*chain)[0].getMin(); x_u[6+0]=(*chain)[0].getMax();
227 x_l[6+1]=(*chain)[2].getMin(); x_u[6+1]=(*chain)[2].getMax();
228 x_l[6+2]=(*chain)[3].getMin(); x_u[6+2]=2.0*(*chain)[3].getMax();
231 chain=problem.index.asChain();
232 x_l[9+0]=(*chain)[0].getMin(); x_u[9+0]=3.0*(*chain)[0].getMax();
233 x_l[9+1]=(*chain)[1].getMin(); x_u[9+1]=(*chain)[1].getMax();
234 x_l[9+2]=(*chain)[2].getMin(); x_u[9+2]=2.0*(*chain)[2].getMax();
237 if (problem.nFingers==3)
239 chain=problem.middle.asChain();
240 x_l[12+0]=(*chain)[0].getMin(); x_u[12+0]=(*chain)[0].getMax();
241 x_l[12+1]=(*chain)[1].getMin(); x_u[12+1]=2.0*(*chain)[1].getMax();
245 g_l[0]=1.0; g_u[0]=1e20;
257 if (problem.nFingers==3)
264 bool get_starting_point(Ipopt::Index n,
bool init_x, Ipopt::Number *x,
265 bool init_z, Ipopt::Number *z_L, Ipopt::Number *z_U,
266 Ipopt::Index m,
bool init_lambda, Ipopt::Number *lambda)
269 x[0]=guess.xyz_ee[0];
270 x[1]=guess.xyz_ee[1];
271 x[2]=guess.xyz_ee[2];
274 x[3+0]=guess.rpy_ee[0]-rpy_offs[0];
275 x[3+1]=guess.rpy_ee[1]-rpy_offs[1];
276 x[3+2]=guess.rpy_ee[2]-rpy_offs[2];
279 x[6+0]=guess.joints[0];
280 x[6+1]=guess.joints[1];
281 x[6+2]=guess.joints[2];
284 x[9+0]=guess.joints[3+0];
285 x[9+1]=guess.joints[3+1];
286 x[9+2]=guess.joints[3+2];
289 if (problem.nFingers==3)
291 x[12+0]=guess.joints[6+0];
292 x[12+1]=guess.joints[6+1];
299 bool eval_f(Ipopt::Index n,
const Ipopt::Number *x,
bool new_x,
300 Ipopt::Number &obj_value)
302 computeQuantities(x);
304 obj_value=2.0+dot(problem.normalDirs[0],Hc*thumbH_col2)+
305 dot(problem.normalDirs[1],Hc*indexH_col2);
317 if (problem.nFingers==3)
319 obj_value+=1.0+dot(problem.normalDirs[2],Hc*middleH_col2);
330 bool eval_grad_f(Ipopt::Index n,
const Ipopt::Number* x,
bool new_x,
331 Ipopt::Number *grad_f)
333 computeQuantities(x);
342 grad_f[3]=dot(problem.normalDirs[0],dHc_dx3*thumbH_col2)+
343 dot(problem.normalDirs[1],dHc_dx3*indexH_col2);
345 grad_f[4]=dot(problem.normalDirs[0],dHc_dx4*thumbH_col2)+
346 dot(problem.normalDirs[1],dHc_dx4*indexH_col2);
348 grad_f[5]=dot(problem.normalDirs[0],dHc_dx5*thumbH_col2)+
349 dot(problem.normalDirs[1],dHc_dx5*indexH_col2);
351 if (problem.nFingers==3)
353 grad_f[3]+=dot(problem.normalDirs[2],dHc_dx3*middleH_col2);
354 grad_f[4]+=dot(problem.normalDirs[2],dHc_dx4*middleH_col2);
355 grad_f[5]+=dot(problem.normalDirs[2],dHc_dx5*middleH_col2);
359 Matrix thumbJ=problem.thumb.AnaJacobian(2).removeRows(4,2);
360 thumbJ.setRow(3,Vector(thumbJ.cols(),0.0));
361 grad_f[6]=dot(problem.normalDirs[0],Hc*thumbJ.getCol(0));
362 grad_f[7]=dot(problem.normalDirs[0],Hc*thumbJ.getCol(1));
363 grad_f[8]=dot(problem.normalDirs[0],Hc*thumbJ.getCol(2))/2.0+
364 dot(problem.normalDirs[0],Hc*thumbJ.getCol(3))/2.0;
371 Matrix indexJ=problem.index.AnaJacobian(2).removeRows(4,2);
372 indexJ.setRow(3,Vector(indexJ.cols(),0.0));
373 grad_f[9] =dot(problem.normalDirs[1],Hc*indexJ.getCol(0))/3.0;
374 grad_f[10]=dot(problem.normalDirs[1],Hc*indexJ.getCol(1));
375 grad_f[11]=dot(problem.normalDirs[1],Hc*indexJ.getCol(2))/2.0+
376 dot(problem.normalDirs[1],Hc*indexJ.getCol(3))/2.0;
383 if (problem.nFingers==3)
385 Matrix middleJ=problem.middle.AnaJacobian(2).removeRows(4,2);
386 middleJ.setRow(3,Vector(middleJ.cols(),0.0));
387 grad_f[12]=dot(problem.normalDirs[2],Hc*middleJ.getCol(0));
388 grad_f[13]=dot(problem.normalDirs[2],Hc*middleJ.getCol(1))/2.0+
389 dot(problem.normalDirs[2],Hc*middleJ.getCol(2))/2.0;
400 bool eval_g(Ipopt::Index n,
const Ipopt::Number *x,
bool new_x,
401 Ipopt::Index m, Ipopt::Number *g)
403 computeQuantities(x);
406 double tmp1,tmp2,tmp3;
407 tmp1=x[0]/problem.dimensions[0];
408 tmp2=x[1]/problem.dimensions[1];
409 tmp3=x[2]/problem.dimensions[2];
410 g[0]=tmp1*tmp1+tmp2*tmp2+tmp3*tmp3;
413 g[1]=norm2(problem.contactPoints[0]-Hc*thumbH_col3);
414 g[2]=norm2(problem.contactPoints[1]-Hc*indexH_col3);
433 if (problem.nFingers==3)
434 g[3]=norm2(problem.contactPoints[2]-Hc*middleH_col3);
440 bool eval_jac_g(Ipopt::Index n,
const Ipopt::Number *x,
bool new_x,
441 Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index *iRow,
442 Ipopt::Index *jCol, Ipopt::Number *values)
451 iRow[cnt]=0; jCol[cnt]=0; cnt++;
452 iRow[cnt]=0; jCol[cnt]=1; cnt++;
453 iRow[cnt]=0; jCol[cnt]=2; cnt++;
456 for (
int i=0; i<6; i++, cnt++)
458 iRow[cnt]=1; jCol[cnt]=i;
461 iRow[cnt]=1; jCol[cnt]=6; cnt++;
462 iRow[cnt]=1; jCol[cnt]=7; cnt++;
463 iRow[cnt]=1; jCol[cnt]=8; cnt++;
466 for (
int i=0; i<6; i++, cnt++)
468 iRow[cnt]=2; jCol[cnt]=i;
471 iRow[cnt]=2; jCol[cnt]=9; cnt++;
472 iRow[cnt]=2; jCol[cnt]=10; cnt++;
473 iRow[cnt]=2; jCol[cnt]=11; cnt++;
502 if (problem.nFingers==3)
505 for (
int i=0; i<6; i++, cnt++)
507 iRow[cnt]=3; jCol[cnt]=i;
510 iRow[cnt]=3; jCol[cnt]=12; cnt++;
511 iRow[cnt]=3; jCol[cnt]=13; cnt++;
516 computeQuantities(x);
519 double dim0=(problem.dimensions[0]*problem.dimensions[0])/2.0;
520 double dim1=(problem.dimensions[1]*problem.dimensions[1])/2.0;
521 double dim2=(problem.dimensions[2]*problem.dimensions[2])/2.0;
533 Matrix J=problem.thumb.AnaJacobian(3).removeRows(4,2);
534 J.setRow(3,Vector(J.cols(),0.0));
535 Vector &p=thumbH_col3;
536 Vector tmp=problem.contactPoints[0]-Hc*p;
538 values[cnt+0]=-2.0*dot(tmp,dHc_dx0*p);
539 values[cnt+1]=-2.0*dot(tmp,dHc_dx1*p);
540 values[cnt+2]=-2.0*dot(tmp,dHc_dx2*p);
541 values[cnt+3]=-2.0*dot(tmp,dHc_dx3*p);
542 values[cnt+4]=-2.0*dot(tmp,dHc_dx4*p);
543 values[cnt+5]=-2.0*dot(tmp,dHc_dx5*p);
544 values[cnt+6]=-2.0*dot(tmp,Hc*J.getCol(0));
545 values[cnt+7]=-2.0*dot(tmp,Hc*J.getCol(1));
546 values[cnt+8]=-2.0*dot(tmp,Hc*J.getCol(2))/2.0-dot(tmp,Hc*J.getCol(3))/2.0;
552 Matrix J=problem.index.AnaJacobian(3).removeRows(4,2);
553 J.setRow(3,Vector(J.cols(),0.0));
554 Vector &p=indexH_col3;
555 Vector tmp=problem.contactPoints[1]-Hc*p;
557 values[cnt+0]=-2.0*dot(tmp,dHc_dx0*p);
558 values[cnt+1]=-2.0*dot(tmp,dHc_dx1*p);
559 values[cnt+2]=-2.0*dot(tmp,dHc_dx2*p);
560 values[cnt+3]=-2.0*dot(tmp,dHc_dx3*p);
561 values[cnt+4]=-2.0*dot(tmp,dHc_dx4*p);
562 values[cnt+5]=-2.0*dot(tmp,dHc_dx5*p);
563 values[cnt+6]=-2.0*dot(tmp,Hc*J.getCol(0))/3.0;
564 values[cnt+7]=-2.0*dot(tmp,Hc*J.getCol(1));
565 values[cnt+8]=-2.0*dot(tmp,Hc*J.getCol(2))/2.0-dot(tmp,Hc*J.getCol(3))/2.0;
639 if (problem.nFingers==3)
641 Matrix J=problem.middle.AnaJacobian(3).removeRows(4,2);
642 J.setRow(3,Vector(J.cols(),0.0));
643 Vector &p=middleH_col3;
644 Vector tmp=problem.contactPoints[2]-Hc*p;
646 values[cnt+0]=-2.0*dot(tmp,dHc_dx0*p);
647 values[cnt+1]=-2.0*dot(tmp,dHc_dx1*p);
648 values[cnt+2]=-2.0*dot(tmp,dHc_dx2*p);
649 values[cnt+3]=-2.0*dot(tmp,dHc_dx3*p);
650 values[cnt+4]=-2.0*dot(tmp,dHc_dx4*p);
651 values[cnt+5]=-2.0*dot(tmp,dHc_dx5*p);
652 values[cnt+6]=-2.0*dot(tmp,Hc*J.getCol(0));
653 values[cnt+7]=-2.0*dot(tmp,Hc*J.getCol(1))/2.0-dot(tmp,Hc*J.getCol(2))/2.0;
661 bool eval_h(Ipopt::Index n,
const Ipopt::Number *x,
bool new_x,
662 Ipopt::Number obj_factor, Ipopt::Index m,
const Ipopt::Number *lambda,
663 bool new_lambda, Ipopt::Index nele_hess, Ipopt::Index *iRow,
664 Ipopt::Index *jCol, Ipopt::Number *values)
670 bool get_scaling_parameters(Ipopt::Number &obj_scaling,
bool &use_x_scaling,
671 Ipopt::Index n, Ipopt::Number *x_scaling,
672 bool &use_g_scaling, Ipopt::Index m,
673 Ipopt::Number *g_scaling)
679 for (
int i=0; i<m; i++)
686 void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n,
687 const Ipopt::Number *x,
const Ipopt::Number *z_L,
688 const Ipopt::Number *z_U, Ipopt::Index m,
689 const Ipopt::Number *g,
const Ipopt::Number *lambda,
690 Ipopt::Number obj_value,
const Ipopt::IpoptData *ip_data,
691 Ipopt::IpoptCalculatedQuantities *ip_cq)
694 solution.xyz_ee[0]=x[0];
695 solution.xyz_ee[1]=x[1];
696 solution.xyz_ee[2]=x[2];
699 solution.rpy_ee[0]=x[3+0]+rpy_offs[0];
700 solution.rpy_ee[1]=x[3+1]+rpy_offs[1];
701 solution.rpy_ee[2]=x[3+2]+rpy_offs[2];
704 solution.joints[0]=x[6+0];
705 solution.joints[1]=x[6+1];
706 solution.joints[2]=x[6+2];
709 solution.joints[3+0]=x[9+0];
710 solution.joints[3+1]=x[9+1];
711 solution.joints[3+2]=x[9+2];
714 if (problem.nFingers==3)
716 solution.joints[6+0]=x[12+0];
717 solution.joints[6+1]=x[12+1];
720 Ipopt::Number cost_fun;
721 eval_f(n,x,
true,cost_fun);
722 solution.cost_fun=cost_fun;
728 void HandIK_Variables::print()
730 printf(
"xyz_ee = (%s) [m]\n",xyz_ee.toString(3,3).c_str());
731 printf(
"rpy_ee = (%s) [deg]\n",(CTRL_RAD2DEG*rpy_ee).toString(3,3).c_str());
732 printf(
"joints = (%s) [deg]\n",(CTRL_RAD2DEG*joints).toString(3,3).c_str());
737 bool HandIK_Solver::setInitialGuess(
const HandIK_Variables &_guess)
745 bool HandIK_Solver::solve(HandIK_Variables &solution)
747 Ipopt::SmartPtr<Ipopt::IpoptApplication> app=
new Ipopt::IpoptApplication;
748 app->Options()->SetNumericValue(
"tol",1e-8);
749 app->Options()->SetNumericValue(
"constr_viol_tol",1e-6);
750 app->Options()->SetIntegerValue(
"acceptable_iter",0);
751 app->Options()->SetStringValue(
"mu_strategy",
"adaptive");
752 app->Options()->SetIntegerValue(
"max_iter",500);
755 app->Options()->SetStringValue(
"nlp_scaling_method",
"user-scaling");
759 app->Options()->SetStringValue(
"hessian_approximation",
"limited-memory");
761 app->Options()->SetIntegerValue(
"print_level",0);
762 app->Options()->SetStringValue(
"derivative_test",
"none");
766 Ipopt::SmartPtr<HandIK_NLP> nlp=
new HandIK_NLP(problem);
768 nlp->setInitialGuess(guess);
769 Ipopt::ApplicationReturnStatus status=app->OptimizeTNLP(GetRawPtr(nlp));
770 solution=nlp->getSolution();
772 return (status==Ipopt::Solve_Succeeded);