iCub-main
Loading...
Searching...
No Matches
nlp.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014 iCub Facility - Istituto Italiano di Tecnologia
3 * Author: Ugo Pattacini
4 * email: ugo.pattacini@iit.it
5 * Permission is granted to copy, distribute, and/or modify this program
6 * under the terms of the GNU General Public License, version 2 or any
7 * later version published by the Free Software Foundation.
8 *
9 * A copy of the license can be found at
10 * http://www.robotcub.org/icub/license/gpl.txt
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 * Public License for more details
16*/
17
18#include <cmath>
19#include <algorithm>
20#include <string>
21#include <deque>
22
23#include <yarp/sig/all.h>
24#include <yarp/dev/all.h>
25#include <yarp/math/Math.h>
26
27#include <iCub/ctrl/math.h>
28
29#include <IpTNLP.hpp>
30#include <nlp.h>
31
32using namespace std;
33using namespace yarp::os;
34using namespace yarp::sig;
35using namespace yarp::math;
36using namespace iCub::ctrl;
37
38
39/****************************************************************/
40Matrix computeH(const Vector &x)
41{
42 Matrix H=rpy2dcm(x.subVector(3,5));
43 H(0,3)=x[0]; H(1,3)=x[1]; H(2,3)=x[2];
44
45 return H;
46}
47
48
49/****************************************************************/
50Matrix computeH(const Ipopt::Number *x)
51{
52 Vector _x(6);
53 for (size_t i=0; i<_x.length(); i++)
54 _x[i]=x[i];
55
56 return computeH(_x);
57}
58
59
60/****************************************************************/
61class EyeAlignerNLP : public Ipopt::TNLP
62{
63protected:
64 const deque<Vector> &p2d;
65 const deque<Vector> &p3d;
66 const Matrix &Prj;
67
68 Vector min;
69 Vector max;
70 Vector x0;
71 Vector x;
72
73public:
74 /****************************************************************/
75 EyeAlignerNLP(const deque<Vector> &_p2d,
76 const deque<Vector> &_p3d,
77 const Vector &_min, const Vector &_max,
78 const Matrix &_Prj) :
79 p2d(_p2d), p3d(_p3d), Prj(_Prj)
80 {
81 min=_min;
82 max=_max;
83 x0=0.5*(min+max);
84 }
85
86 /****************************************************************/
87 void set_x0(const Vector &x0)
88 {
89 size_t len=std::min(this->x0.length(),x0.length());
90 for (size_t i=0; i<len; i++)
91 this->x0[i]=x0[i];
92 }
93
94 /****************************************************************/
95 Vector get_result() const
96 {
97 return x;
98 }
99
100 /****************************************************************/
101 bool get_nlp_info(Ipopt::Index &n, Ipopt::Index &m, Ipopt::Index &nnz_jac_g,
102 Ipopt::Index &nnz_h_lag, IndexStyleEnum &index_style)
103 {
104 n=6;
105 m=nnz_jac_g=nnz_h_lag=0;
106 index_style=TNLP::C_STYLE;
107
108 return true;
109 }
110
111 /****************************************************************/
112 bool get_bounds_info(Ipopt::Index n, Ipopt::Number *x_l, Ipopt::Number *x_u,
113 Ipopt::Index m, Ipopt::Number *g_l, Ipopt::Number *g_u)
114 {
115 for (Ipopt::Index i=0; i<n; i++)
116 {
117 x_l[i]=min[i];
118 x_u[i]=max[i];
119 }
120
121 return true;
122 }
123
124 /****************************************************************/
125 bool get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number *x,
126 bool init_z, Ipopt::Number *z_L, Ipopt::Number *z_U,
127 Ipopt::Index m, bool init_lambda, Ipopt::Number *lambda)
128 {
129 for (Ipopt::Index i=0; i<n; i++)
130 x[i]=x0[i];
131
132 return true;
133 }
134
135 /****************************************************************/
136 bool eval_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
137 Ipopt::Number &obj_value)
138 {
139 Matrix PrjH=Prj*SE3inv(computeH(x));
140
141 obj_value=0.0;
142 if (p2d.size()>0)
143 {
144 for (size_t i=0; i<p2d.size(); i++)
145 {
146 Vector p2di=PrjH*p3d[i];
147 p2di=p2di/p2di[2];
148 p2di.pop_back();
149
150 obj_value+=norm2(p2d[i]-p2di);
151 }
152
153 obj_value/=p2d.size();
154 }
155
156 return true;
157 }
158
159 /****************************************************************/
160 bool eval_grad_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
161 Ipopt::Number *grad_f)
162 {
163 double roll=x[3]; double cr=cos(roll); double sr=sin(roll);
164 double pitch=x[4]; double cp=cos(pitch); double sp=sin(pitch);
165 double yaw=x[5]; double cy=cos(yaw); double sy=sin(yaw);
166
167 Matrix Rz=eye(4,4);
168 Rz(0,0)=cy; Rz(1,1)=cy; Rz(0,1)=-sy; Rz(1,0)=sy;
169 Matrix dRz=zeros(4,4);
170 dRz(0,0)=-sy; dRz(1,1)=-sy; dRz(0,1)=-cy; dRz(1,0)=cy;
171
172 Matrix Ry=eye(4,4);
173 Ry(0,0)=cp; Ry(2,2)=cp; Ry(0,2)=sp; Ry(2,0)=-sp;
174 Matrix dRy=zeros(4,4);
175 dRy(0,0)=-sp; dRy(2,2)=-sp; dRy(0,2)=cp; dRy(2,0)=-cp;
176
177 Matrix Rx=eye(4,4);
178 Rx(1,1)=cr; Rx(2,2)=cr; Rx(1,2)=-sr; Rx(2,1)=sr;
179 Matrix dRx=zeros(4,4);
180 dRx(1,1)=-sr; dRx(2,2)=-sr; dRx(1,2)=-cr; dRx(2,1)=cr;
181
182 Matrix invRz=Rz.transposed();
183 Matrix invRy=Ry.transposed();
184 Matrix invRx=Rx.transposed();
185
186 Matrix invR=(-1.0)*invRx*invRy*invRz;
187 Vector p(4,-1.0); p[0]=-x[0]; p[1]=-x[1]; p[2]=-x[2];
188
189 Matrix dHdx0=zeros(4,4); dHdx0.setCol(3,invR.getCol(0));
190 Matrix dHdx1=zeros(4,4); dHdx1.setCol(3,invR.getCol(1));
191 Matrix dHdx2=zeros(4,4); dHdx2.setCol(3,invR.getCol(2));
192 Matrix dHdx3=dRx.transposed()*invRy*invRz; dHdx3.setCol(3,dHdx3*p);
193 Matrix dHdx4=invRx*dRy.transposed()*invRz; dHdx4.setCol(3,dHdx4*p);
194 Matrix dHdx5=invRx*invRy*dRz.transposed(); dHdx5.setCol(3,dHdx5*p);
195
196 Matrix dPrjHdx0=Prj*dHdx0;
197 Matrix dPrjHdx1=Prj*dHdx1;
198 Matrix dPrjHdx2=Prj*dHdx2;
199 Matrix dPrjHdx3=Prj*dHdx3;
200 Matrix dPrjHdx4=Prj*dHdx4;
201 Matrix dPrjHdx5=Prj*dHdx5;
202
203 Matrix PrjH=Prj*SE3inv(computeH(x));
204
205 grad_f[0]=grad_f[1]=grad_f[2]=0.0;
206 grad_f[3]=grad_f[4]=grad_f[5]=0.0;
207 if (p2d.size()>0)
208 {
209 for (size_t i=0; i<p2d.size(); i++)
210 {
211 Vector p2di=PrjH*p3d[i];
212 p2di=p2di/p2di[2];
213 p2di.pop_back();
214
215 Vector d=p2d[i]-p2di;
216
217 double u_num=dot(PrjH.getRow(0),p3d[i]);
218 double v_num=dot(PrjH.getRow(1),p3d[i]);
219 double lambda=dot(PrjH.getRow(2),p3d[i]);
220 double lambda2=lambda*lambda;
221 double tmp_dot;
222
223 Vector dp2d_dx0(2);
224 tmp_dot=dot(dPrjHdx0.getRow(2),p3d[i]);
225 dp2d_dx0[0]=(dot(dPrjHdx0.getRow(0),p3d[i])*lambda-tmp_dot*u_num)/lambda2;
226 dp2d_dx0[1]=(dot(dPrjHdx0.getRow(1),p3d[i])*lambda-tmp_dot*v_num)/lambda2;
227
228 Vector dp2d_dx1(2);
229 tmp_dot=dot(dPrjHdx1.getRow(2),p3d[i]);
230 dp2d_dx1[0]=(dot(dPrjHdx1.getRow(0),p3d[i])*lambda-tmp_dot*u_num)/lambda2;
231 dp2d_dx1[1]=(dot(dPrjHdx1.getRow(1),p3d[i])*lambda-tmp_dot*v_num)/lambda2;
232
233 Vector dp2d_dx2(2);
234 tmp_dot=dot(dPrjHdx2.getRow(2),p3d[i]);
235 dp2d_dx2[0]=(dot(dPrjHdx2.getRow(0),p3d[i])*lambda-tmp_dot*u_num)/lambda2;
236 dp2d_dx2[1]=(dot(dPrjHdx2.getRow(1),p3d[i])*lambda-tmp_dot*v_num)/lambda2;
237
238 Vector dp2d_dx3(2);
239 tmp_dot=dot(dPrjHdx3.getRow(2),p3d[i]);
240 dp2d_dx3[0]=(dot(dPrjHdx3.getRow(0),p3d[i])*lambda-tmp_dot*u_num)/lambda2;
241 dp2d_dx3[1]=(dot(dPrjHdx3.getRow(1),p3d[i])*lambda-tmp_dot*v_num)/lambda2;
242
243 Vector dp2d_dx4(2);
244 tmp_dot=dot(dPrjHdx4.getRow(2),p3d[i]);
245 dp2d_dx4[0]=(dot(dPrjHdx4.getRow(0),p3d[i])*lambda-tmp_dot*u_num)/lambda2;
246 dp2d_dx4[1]=(dot(dPrjHdx4.getRow(1),p3d[i])*lambda-tmp_dot*v_num)/lambda2;
247
248 Vector dp2d_dx5(2);
249 tmp_dot=dot(dPrjHdx5.getRow(2),p3d[i]);
250 dp2d_dx5[0]=(dot(dPrjHdx5.getRow(0),p3d[i])*lambda-tmp_dot*u_num)/lambda2;
251 dp2d_dx5[1]=(dot(dPrjHdx5.getRow(1),p3d[i])*lambda-tmp_dot*v_num)/lambda2;
252
253 grad_f[0]-=2.0*dot(d,dp2d_dx0);
254 grad_f[1]-=2.0*dot(d,dp2d_dx1);
255 grad_f[2]-=2.0*dot(d,dp2d_dx2);
256 grad_f[3]-=2.0*dot(d,dp2d_dx3);
257 grad_f[4]-=2.0*dot(d,dp2d_dx4);
258 grad_f[5]-=2.0*dot(d,dp2d_dx5);
259 }
260
261 for (Ipopt::Index i=0; i<n; i++)
262 grad_f[i]/=p2d.size();
263 }
264
265 return true;
266 }
267
268 /****************************************************************/
269 bool eval_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
270 Ipopt::Index m, Ipopt::Number *g)
271 {
272 return true;
273 }
274
275 /****************************************************************/
276 bool eval_jac_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
277 Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index *iRow,
278 Ipopt::Index *jCol, Ipopt::Number *values)
279 {
280 return true;
281 }
282
283
284 /****************************************************************/
285 bool eval_h(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
286 Ipopt::Number obj_factor, Ipopt::Index m, const Ipopt::Number *lambda,
287 bool new_lambda, Ipopt::Index nele_hess, Ipopt::Index *iRow,
288 Ipopt::Index *jCol, Ipopt::Number *values)
289 {
290 return true;
291 }
292
293
294 /****************************************************************/
295 void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n,
296 const Ipopt::Number *x, const Ipopt::Number *z_L,
297 const Ipopt::Number *z_U, Ipopt::Index m,
298 const Ipopt::Number *g, const Ipopt::Number *lambda,
299 Ipopt::Number obj_value, const Ipopt::IpoptData *ip_data,
300 Ipopt::IpoptCalculatedQuantities *ip_cq)
301 {
302 this->x.resize(n);
303 for (Ipopt::Index i=0; i<n; i++)
304 this->x[i]=x[i];
305 }
306};
307
308
309
310/****************************************************************/
311EyeAligner::EyeAligner() : Prj(eye(3,4))
312{
313 min.resize(6); max.resize(6);
314 min[0]=-1.0; max[0]=1.0;
315 min[1]=-1.0; max[1]=1.0;
316 min[2]=-1.0; max[2]=1.0;
317 min[3]=-M_PI; max[3]=M_PI;
318 min[4]=-M_PI; max[4]=M_PI;
319 min[5]=-M_PI; max[5]=M_PI;
320
321 x0=0.5*(min+max);
322 Prj.resize(3,4); Prj.zero();
323}
324
325
326/****************************************************************/
327double EyeAligner::evalError(const Matrix &H)
328{
329 Matrix PrjH=Prj*SE3inv(H);
330
331 double error=0.0;
332 if (p2d.size()>0)
333 {
334 for (size_t i=0; i<p2d.size(); i++)
335 {
336 Vector p2di=PrjH*p3d[i];
337 p2di=p2di/p2di[2];
338 p2di.pop_back();
339
340 error+=norm(p2d[i]-p2di);
341 }
342
343 error/=p2d.size();
344 }
345
346 return error;
347}
348
349
350/****************************************************************/
351bool EyeAligner::setProjection(const Matrix &Prj)
352{
353 if ((Prj.rows()>=3) && (Prj.cols()>=4))
354 {
355 this->Prj=Prj.submatrix(0,2,0,3);
356 return true;
357 }
358 else
359 return false;
360}
361
362
363/****************************************************************/
365{
366 return Prj;
367}
368
369
370/****************************************************************/
371void EyeAligner::setBounds(const Vector &min, const Vector &max)
372{
373 size_t len_min=std::min(this->min.length(),min.length());
374 size_t len_max=std::min(this->max.length(),max.length());
375
376 for (size_t i=0; i<len_min; i++)
377 this->min[i]=min[i];
378
379 for (size_t i=0; i<len_max; i++)
380 this->max[i]=max[i];
381}
382
383
384/****************************************************************/
385bool EyeAligner::addPoints(const Vector &p2di, const Vector &p3di)
386{
387 if ((p2di.length()>=2) && (p3di.length()>=4))
388 {
389 p2d.push_back(p2di.subVector(0,1));
390 p3d.push_back(p3di.subVector(0,3));
391
392 return true;
393 }
394 else
395 return false;
396}
397
398
399/****************************************************************/
401{
402 p2d.clear();
403 p3d.clear();
404}
405
406
407/****************************************************************/
409{
410 return p2d.size();
411}
412
413
414/****************************************************************/
416{
417 if ((H.rows()>=4) && (H.cols()>=4))
418 {
419 Vector rpy=dcm2rpy(H);
420 x0[0]=H(0,3); x0[1]=H(1,3); x0[2]=H(2,3);
421 x0[3]=rpy[0]; x0[4]=rpy[1]; x0[5]=rpy[2];
422
423 for (size_t i=0; i<min.length(); i++)
424 x0[i]=std::min(std::max(x0[i],min[i]),max[i]);
425
426 return true;
427 }
428 else
429 return false;
430}
431
432
433/****************************************************************/
434bool EyeAligner::calibrate(Matrix &H, double &error, const int max_iter,
435 const int print_level, const string &derivative_test)
436{
437 if (p2d.size()>0)
438 {
439 Ipopt::SmartPtr<Ipopt::IpoptApplication> app=new Ipopt::IpoptApplication;
440 app->Options()->SetNumericValue("tol",1e-8);
441 app->Options()->SetIntegerValue("acceptable_iter",0);
442 app->Options()->SetStringValue("mu_strategy","adaptive");
443 app->Options()->SetIntegerValue("max_iter",max_iter);
444 app->Options()->SetStringValue("nlp_scaling_method","gradient-based");
445 app->Options()->SetStringValue("hessian_approximation","limited-memory");
446 app->Options()->SetIntegerValue("print_level",print_level);
447 app->Options()->SetStringValue("derivative_test",derivative_test.c_str());
448 app->Options()->SetStringValue("derivative_test_print_all","yes");
449 app->Initialize();
450
451 Ipopt::SmartPtr<EyeAlignerNLP> nlp=new EyeAlignerNLP(p2d,p3d,min,max,Prj);
452
453 nlp->set_x0(x0);
454 Ipopt::ApplicationReturnStatus status=app->OptimizeTNLP(GetRawPtr(nlp));
455
456 Vector x=nlp->get_result();
457 H=computeH(x);
459
460 return (status==Ipopt::Solve_Succeeded);
461 }
462 else
463 return false;
464}
465
466
#define M_PI
Definition XSensMTx.cpp:24
bool eval_h(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number obj_factor, Ipopt::Index m, const Ipopt::Number *lambda, bool new_lambda, Ipopt::Index nele_hess, Ipopt::Index *iRow, Ipopt::Index *jCol, Ipopt::Number *values)
Definition nlp.cpp:285
const deque< Vector > & p3d
Definition nlp.cpp:65
const Matrix & Prj
Definition nlp.cpp:66
bool get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number *x, bool init_z, Ipopt::Number *z_L, Ipopt::Number *z_U, Ipopt::Index m, bool init_lambda, Ipopt::Number *lambda)
Definition nlp.cpp:125
Vector x0
Definition nlp.cpp:70
Vector min
Definition nlp.cpp:68
bool eval_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Number *g)
Definition nlp.cpp:269
const deque< Vector > & p2d
Definition nlp.cpp:64
Vector x
Definition nlp.cpp:71
bool eval_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number &obj_value)
Definition nlp.cpp:136
bool eval_grad_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number *grad_f)
Definition nlp.cpp:160
bool get_bounds_info(Ipopt::Index n, Ipopt::Number *x_l, Ipopt::Number *x_u, Ipopt::Index m, Ipopt::Number *g_l, Ipopt::Number *g_u)
Definition nlp.cpp:112
void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n, const Ipopt::Number *x, const Ipopt::Number *z_L, const Ipopt::Number *z_U, Ipopt::Index m, const Ipopt::Number *g, const Ipopt::Number *lambda, Ipopt::Number obj_value, const Ipopt::IpoptData *ip_data, Ipopt::IpoptCalculatedQuantities *ip_cq)
Definition nlp.cpp:295
void set_x0(const Vector &x0)
Definition nlp.cpp:87
bool get_nlp_info(Ipopt::Index &n, Ipopt::Index &m, Ipopt::Index &nnz_jac_g, Ipopt::Index &nnz_h_lag, IndexStyleEnum &index_style)
Definition nlp.cpp:101
bool eval_jac_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index *iRow, Ipopt::Index *jCol, Ipopt::Number *values)
Definition nlp.cpp:276
Vector get_result() const
Definition nlp.cpp:95
Vector max
Definition nlp.cpp:69
EyeAlignerNLP(const deque< Vector > &_p2d, const deque< Vector > &_p3d, const Vector &_min, const Vector &_max, const Matrix &_Prj)
Definition nlp.cpp:75
bool setInitialGuess(const yarp::sig::Matrix &H)
Definition nlp.cpp:415
yarp::sig::Matrix Prj
Definition nlp.h:42
yarp::sig::Vector max
Definition nlp.h:40
std::deque< yarp::sig::Vector > p3d
Definition nlp.h:45
size_t getNumPoints() const
Definition nlp.cpp:408
yarp::sig::Vector x0
Definition nlp.h:41
void setBounds(const yarp::sig::Vector &min, const yarp::sig::Vector &max)
Definition nlp.cpp:371
double evalError(const yarp::sig::Matrix &H)
Definition nlp.cpp:327
bool calibrate(yarp::sig::Matrix &H, double &error, const int max_iter=ALIGN_IPOPT_MAX_ITER, const int print_level=0, const std::string &derivative_test="none")
Definition nlp.cpp:434
EyeAligner()
Definition nlp.cpp:311
bool addPoints(const yarp::sig::Vector &p2di, const yarp::sig::Vector &p3di)
Definition nlp.cpp:385
yarp::sig::Vector min
Definition nlp.h:39
bool setProjection(const yarp::sig::Matrix &Prj)
Definition nlp.cpp:351
std::deque< yarp::sig::Vector > p2d
Definition nlp.h:44
void clearPoints()
Definition nlp.cpp:400
yarp::sig::Matrix getProjection() const
Definition nlp.cpp:364
zeros(2, 2) eye(2
int n
bool error
double dot(const yarp::sig::Matrix &A, int colA, const yarp::sig::Matrix &B, int colB)
Returns the dot product between two vectors given in the form: matrix(:,col).
double norm2(const yarp::sig::Matrix &M, int col)
Returns the squared norm of the vector given in the form: matrix(:,col).
Definition math.h:91
double norm(const yarp::sig::Matrix &M, int col)
Returns the norm of the vector given in the form: matrix(:,col).
Matrix computeH(const Vector &x)
Definition nlp.cpp:40
yarp::sig::Matrix computeH(const yarp::sig::Vector &x)