iCub-main
pointing_far.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 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 <string>
19 #include <cmath>
20 #include <limits>
21 
22 #include <IpTNLP.hpp>
23 #include <IpIpoptApplication.hpp>
24 
25 #include <yarp/os/Property.h>
26 #include <yarp/os/LogStream.h>
27 #include <yarp/dev/CartesianControl.h>
28 #include <yarp/sig/Vector.h>
29 #include <yarp/sig/Matrix.h>
30 #include <yarp/math/Math.h>
31 
32 #include <iCub/iKin/iKinFwd.h>
33 #include <iCub/pointing_far.h>
34 
35 #define RAD2DEG (180.0/M_PI)
36 #define DEG2RAD (M_PI/180.0)
37 
38 using namespace std;
39 using namespace yarp::os;
40 using namespace yarp::dev;
41 using namespace yarp::sig;
42 using namespace yarp::math;
43 using namespace iCub::iKin;
44 
45 
46 /*************************************************************************/
47 class PointingFarNLP : public Ipopt::TNLP
48 {
49  iCubArm *finger_tip;
50  iCubArm *elbow;
51  iCubFinger *finger;
52  Vector point;
53 
54 public:
55  /*********************************************************************/
56  PointingFarNLP(ICartesianControl *iarm) :
57  point(3,0.0)
58  {
59  Bottle info;
60  iarm->getInfo(info);
61  string hand=info.find("arm_type").asString();
62  finger_tip=new iCubArm(hand);
63  elbow=new iCubArm(hand);
64 
65  size_t underscore=hand.find('_');
66  if (underscore!=string::npos)
67  hand=hand.substr(0,underscore);
68 
69  // update joints limits
70  for (unsigned int i=0; i<finger_tip->getN(); i++)
71  {
72  double min,max;
73  iarm->getLimits(i,&min,&max);
74  (*finger_tip->asChain())[i].setMin(DEG2RAD*min);
75  (*finger_tip->asChain())[i].setMax(DEG2RAD*max);
76  (*elbow->asChain())[i].setMin(DEG2RAD*min);
77  (*elbow->asChain())[i].setMax(DEG2RAD*max);
78  }
79 
80  // finger_tip: block torso
81  finger_tip->blockLink(0,0.0);
82  finger_tip->blockLink(1,0.0);
83  finger_tip->blockLink(2,0.0);
84 
85  // finger_tip: block wrist
86  finger_tip->blockLink(8,0.0);
87  finger_tip->blockLink(9,0.0);
88 
89  // elbow: block torso
90  elbow->blockLink(0,0.0);
91  elbow->blockLink(1,0.0);
92  elbow->blockLink(2,0.0);
93 
94  // elbow: remove forearm
95  for (auto i=0; i<4; i++)
96  elbow->asChain()->rmLink(7);
97 
98  // remove all constraints
99  finger_tip->asChain()->setAllConstraints(false);
100  elbow->asChain()->setAllConstraints(false);
101 
102  finger=new iCubFinger(hand+"_index");
103  finger->asChain()->setAllConstraints(false);
104  setFingerJoints(zeros(16));
105  }
106 
107  /*********************************************************************/
108  virtual ~PointingFarNLP()
109  {
110  delete finger_tip;
111  delete elbow;
112  delete finger;
113  }
114 
115  /*********************************************************************/
116  void setPoint(const Vector& point)
117  {
118  this->point=point;
119  }
120 
121  /*********************************************************************/
122  void setFingerJoints(const Vector& finger_joints)
123  {
124  Vector chain_joints;
125  finger->getChainJoints(finger_joints,chain_joints);
126  finger->setAng(DEG2RAD*chain_joints);
127 
128  // add final transformations
129  finger_tip->asChain()->setHN(finger->getH());
130  }
131 
132  /*********************************************************************/
133  void getResult(Vector &q, Vector &x) const
134  {
135  q.resize(finger_tip->getN());
136  for (unsigned int i=0; i<q.length(); i++)
137  q[i]=RAD2DEG*finger_tip->getAng(i);
138  x=finger_tip->EndEffPose();
139  }
140 
141  /*********************************************************************/
142  bool get_nlp_info(Ipopt::Index& n, Ipopt::Index& m, Ipopt::Index& nnz_jac_g,
143  Ipopt::Index& nnz_h_lag, IndexStyleEnum& index_style)
144  {
145  n=finger_tip->getDOF();
146  m=2;
147  nnz_jac_g=m*n;
148  nnz_h_lag=0;
149  index_style=TNLP::C_STYLE;
150  return true;
151  }
152 
153  /*********************************************************************/
154  bool get_bounds_info(Ipopt::Index n, Ipopt::Number* x_l, Ipopt::Number* x_u,
155  Ipopt::Index m, Ipopt::Number* g_l, Ipopt::Number* g_u)
156  {
157  for (Ipopt::Index i=0; i<n; i++)
158  {
159  x_l[i]=(*finger_tip->asChain())(i).getMin();
160  x_u[i]=(*finger_tip->asChain())(i).getMax();
161  }
162 
163  g_l[0]=0.9999;
165 
167  g_u[1]=0.0;
168  return true;
169  }
170 
171  /*********************************************************************/
172  bool get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number* x,
173  bool init_z, Ipopt::Number* z_L, Ipopt::Number* z_U,
174  Ipopt::Index m, bool init_lambda, Ipopt::Number* lambda)
175  {
176  for (Ipopt::Index i=0; i<n; i++)
177  x[i]=0.5*((*finger_tip->asChain())(i).getMin()+
178  (*finger_tip->asChain())(i).getMax());
179  return true;
180  }
181 
182  /*********************************************************************/
183  void setAng(const Ipopt::Number* x)
184  {
185  Vector q(finger_tip->getDOF());
186  for (size_t i=0; i<q.length(); i++)
187  q[i]=x[i];
188  finger_tip->setAng(q);
189  elbow->asChain()->setAng(q);
190  }
191 
192  /*********************************************************************/
193  bool eval_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
194  Ipopt::Number& obj_value)
195  {
196  setAng(x);
197  Matrix tip=finger_tip->getH();
198  double e=-1.0-tip(2,2);
199  obj_value=e*e;
200  return true;
201  }
202 
203  /*********************************************************************/
204  bool eval_grad_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
205  Ipopt::Number* grad_f)
206  {
207  setAng(x);
208  Matrix tip=finger_tip->getH();
209  double e=-1.0-tip(2,2);
210  Matrix dtipZ=finger_tip->AnaJacobian(2);
211  for (Ipopt::Index i=0; i<n; i++)
212  grad_f[i]=-2.0*e*dtipZ(2,i);
213  return true;
214  }
215 
216  /*********************************************************************/
217  bool eval_g(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
218  Ipopt::Index m, Ipopt::Number* g)
219  {
220  setAng(x);
221  Vector elbowPos=elbow->asChain()->EndEffPosition();
222  Vector pe_dir=point-elbowPos;
223 
224  Matrix tip=finger_tip->getH();
225  Vector te_dir=tip.getCol(3).subVector(0,2)-elbowPos;
226  g[0]=dot(pe_dir,te_dir)/(norm(pe_dir)*norm(te_dir));
227 
228  Vector pt_dir=point-tip.getCol(3).subVector(0,2);
229  g[1]=pt_dir[0];
230  return true;
231  }
232 
233  /*********************************************************************/
234  bool eval_jac_g(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
235  Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index* iRow,
236  Ipopt::Index *jCol, Ipopt::Number* values)
237  {
238  if (!values)
239  {
240  Ipopt::Index idx=0;
241  for (Ipopt::Index i=0; i<n; i++,idx++)
242  {
243  iRow[idx]=0;
244  jCol[idx]=i;
245  }
246  for (Ipopt::Index i=0; i<n; i++,idx++)
247  {
248  iRow[idx]=1;
249  jCol[idx]=i;
250  }
251  }
252  else
253  {
254  setAng(x);
255  Vector elbowPos=elbow->asChain()->EndEffPosition();
256  Vector pe_dir=point-elbowPos;
257 
258  Matrix tip=finger_tip->getH();
259  Vector te_dir=tip.getCol(3).subVector(0,2)-elbowPos;
260 
261  Matrix dpe_dir=-1.0*elbow->asChain()->AnaJacobian().removeRows(3,3);
262  dpe_dir=cat(dpe_dir,zeros(3,finger_tip->getDOF()-elbow->asChain()->getDOF()));
263  Matrix dte_dir=finger_tip->AnaJacobian().removeRows(3,3)+dpe_dir;
264 
265  double npe=norm(pe_dir);
266  double nte=norm(te_dir);
267  double nn=npe*nte;
268 
269  for (Ipopt::Index i=0; i<n; i++)
270  values[i]=(dot(dpe_dir.getCol(i),te_dir)+dot(pe_dir,dte_dir.getCol(i)))/nn-
271  dot(pe_dir,te_dir)*(dot(pe_dir,dpe_dir.getCol(i))*nte/npe)/(nn*nn);
272 
273  Matrix dtip=-1.0*finger_tip->AnaJacobian();
274  for (Ipopt::Index i=0; i<n; i++)
275  values[n+i]=dtip(0,i);
276  }
277  return true;
278  }
279 
280  /*********************************************************************/
281  bool eval_h(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
282  Ipopt::Number obj_factor, Ipopt::Index m,
283  const Ipopt::Number *lambda, bool new_lambda,
284  Ipopt::Index nele_hess, Ipopt::Index *iRow,
285  Ipopt::Index *jCol, Ipopt::Number *values)
286  {
287  return true;
288  }
289 
290  /*********************************************************************/
291  void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n,
292  const Ipopt::Number* x, const Ipopt::Number* z_L,
293  const Ipopt::Number* z_U, Ipopt::Index m,
294  const Ipopt::Number* g, const Ipopt::Number* lambda,
295  Ipopt::Number obj_value, const Ipopt::IpoptData* ip_data,
296  Ipopt::IpoptCalculatedQuantities* ip_cq)
297  {
298  }
299 };
300 
301 
302 /*************************************************************************/
303 bool PointingFar::compute(ICartesianControl *iarm, const Property& requirements,
304  Vector& q, Vector& x)
305 {
306  if (iarm==NULL)
307  {
308  yError()<<"Cartesian controller not configured";
309  return false;
310  }
311 
312  Bottle *bPoint=requirements.find("point").asList();
313  if (bPoint==NULL)
314  {
315  yError()<<"Target point not provided";
316  return false;
317  }
318 
319  Vector point(3,0.0);
320  for (int i=0; i<bPoint->size(); i++)
321  point[i]=bPoint->get(i).asFloat64();
322 
323  Ipopt::SmartPtr<Ipopt::IpoptApplication> app=new Ipopt::IpoptApplication;
324  app->Options()->SetNumericValue("tol",0.01);
325  app->Options()->SetNumericValue("constr_viol_tol",0.01);
326  app->Options()->SetIntegerValue("acceptable_iter",0);
327  app->Options()->SetStringValue("mu_strategy","adaptive");
328  app->Options()->SetIntegerValue("max_iter",200);
329  app->Options()->SetStringValue("nlp_scaling_method","gradient-based");
330  app->Options()->SetStringValue("hessian_approximation","limited-memory");
331  app->Options()->SetStringValue("derivative_test","none");
332  app->Options()->SetIntegerValue("print_level",0);
333  app->Initialize();
334 
335  Ipopt::SmartPtr<PointingFarNLP> nlp=new PointingFarNLP(iarm);
336 
337  // specify requirements
338  nlp->setPoint(point);
339  if (Bottle *bFingerJoints=requirements.find("finger-joints").asList())
340  {
341  Vector finger_joints(bFingerJoints->size());
342  for (size_t i=0; i<finger_joints.length(); i++)
343  finger_joints[i]=bFingerJoints->get(i).asFloat64();
344  nlp->setFingerJoints(finger_joints);
345  }
346 
347  Ipopt::ApplicationReturnStatus status=app->OptimizeTNLP(GetRawPtr(nlp));
348  nlp->getResult(q,x);
349  return true;
350 }
351 
352 
353 /*************************************************************************/
354 bool PointingFar::point(ICartesianControl *iarm, const Vector& q, const Vector& x)
355 {
356  if ((q.length()>=10) && (x.length()>=7))
357  {
358  int context;
359  iarm->storeContext(&context);
360 
361  // specify all joints
362  Vector dof(10,1.0);
363  iarm->setDOF(dof,dof);
364  for (unsigned int i=0; i<q.length(); i++)
365  iarm->setLimits(i,q[i],q[i]);
366 
367  double traj;
368  iarm->getTrajTime(&traj);
369  iarm->setInTargetTol(0.02);
370  iarm->goToPoseSync(x.subVector(0,2),x.subVector(3,6));
371  iarm->waitMotionDone(0.2,5.0*traj);
372  iarm->stopControl();
373 
374  iarm->restoreContext(context);
375  iarm->deleteContext(context);
376  return true;
377  }
378  else
379  return false;
380 }
381 
382 
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)
PointingFarNLP(ICartesianControl *iarm)
bool eval_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number &obj_value)
virtual ~PointingFarNLP()
bool eval_grad_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number *grad_f)
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)
bool eval_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Number *g)
void setFingerJoints(const Vector &finger_joints)
void setAng(const Ipopt::Number *x)
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)
void setPoint(const Vector &point)
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)
bool get_nlp_info(Ipopt::Index &n, Ipopt::Index &m, Ipopt::Index &nnz_jac_g, Ipopt::Index &nnz_h_lag, IndexStyleEnum &index_style)
void getResult(Vector &q, Vector &x) const
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)
A class for defining the iCub Arm.
Definition: iKinFwd.h:1193
A class for defining the iCub Finger.
Definition: iKinFwd.h:1233
virtual bool getChainJoints(const yarp::sig::Vector &motorEncoders, yarp::sig::Vector &chainJoints)
Retrieves the vector of actual finger's joint values (to be used in conjuction with the iKinLimb meth...
yarp::sig::Matrix getH(const unsigned int i, const bool allLink=false)
Returns the rigid roto-translation matrix from the root reference frame to the ith frame in Denavit-H...
Definition: iKinFwd.cpp:732
bool setHN(const yarp::sig::Matrix &_HN)
Sets HN, the rigid roto-translation matrix from the Nth frame to the end-effector.
Definition: iKinFwd.cpp:580
yarp::sig::Vector EndEffPosition()
Returns the 3D coordinates of end-effector position.
Definition: iKinFwd.cpp:894
yarp::sig::Matrix AnaJacobian(const unsigned int i, unsigned int col)
Returns the analitical Jacobian of the ith link.
Definition: iKinFwd.cpp:911
bool rmLink(const unsigned int i)
Removes the ith Link from the Chain.
Definition: iKinFwd.cpp:321
yarp::sig::Vector EndEffPose(const bool axisRep=true)
Returns the coordinates of end-effector.
Definition: iKinFwd.cpp:850
yarp::sig::Vector getAng()
Returns the current free joint angles values.
Definition: iKinFwd.cpp:611
yarp::sig::Vector setAng(const yarp::sig::Vector &q)
Sets the free joint angles to values of q[i].
unsigned int getN() const
Returns the number of Links belonging to the Chain.
Definition: iKinFwd.h:549
unsigned int getDOF() const
Returns the current number of Chain's DOF.
Definition: iKinFwd.h:556
bool blockLink(const unsigned int i, double Ang)
Blocks the ith Link at the a certain value of its joint angle.
Definition: iKinFwd.cpp:394
void setAllConstraints(bool _constrained)
Sets the constraint status of all chain links.
Definition: iKinFwd.cpp:498
iKinChain * asChain()
Returns a pointer to the Limb seen as Chain object.
Definition: iKinFwd.h:1012
zeros(2, 2) eye(2
int n
static uint32_t idx[BOARD_NUM]
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 norm(const yarp::sig::Matrix &M, int col)
Returns the norm of the vector given in the form: matrix(:,col).
const FSC max
Definition: strain.h:48
const FSC min
Definition: strain.h:49
#define RAD2DEG
#define DEG2RAD
static bool compute(yarp::dev::ICartesianControl *iarm, const yarp::os::Property &requirements, yarp::sig::Vector &q, yarp::sig::Vector &x)
static bool point(yarp::dev::ICartesianControl *iarm, const yarp::sig::Vector &q, const yarp::sig::Vector &x)