00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <trac_ik/nlopt_ik.hpp>
00032 #include <boost/bind.hpp>
00033 #include <boost/function.hpp>
00034 #include <ros/ros.h>
00035 #include <limits>
00036 #include <boost/date_time.hpp>
00037 #include <trac_ik/dual_quaternion.h>
00038 #include <cmath>
00039
00040
00041
00042 namespace NLOPT_IK {
00043
00044 dual_quaternion targetDQ;
00045
00046 double minfunc(const std::vector<double>& x, std::vector<double>& grad, void* data) {
00047
00048
00049
00050
00051
00052 NLOPT_IK *c = (NLOPT_IK *) data;
00053
00054 return c->minJoints(x,grad);
00055 }
00056
00057 double minfuncDQ(const std::vector<double>& x, std::vector<double>& grad, void* data) {
00058
00059
00060
00061
00062 NLOPT_IK *c = (NLOPT_IK *) data;
00063
00064 std::vector<double> vals(x);
00065
00066 double jump=boost::math::tools::epsilon<float>();
00067 double result[1];
00068 c->cartDQError(vals, result);
00069
00070 if (!grad.empty()) {
00071 double v1[1];
00072 for (uint i=0; i<x.size(); i++) {
00073 double original=vals[i];
00074
00075 vals[i]=original+jump;
00076 c->cartDQError(vals, v1);
00077
00078 vals[i]=original;
00079 grad[i]=(v1[0]-result[0])/(2*jump);
00080 }
00081 }
00082
00083 return result[0];
00084 }
00085
00086
00087 double minfuncSumSquared(const std::vector<double>& x, std::vector<double>& grad, void* data) {
00088
00089
00090
00091
00092
00093 NLOPT_IK *c = (NLOPT_IK *) data;
00094
00095 std::vector<double> vals(x);
00096
00097 double jump=boost::math::tools::epsilon<float>();
00098 double result[1];
00099 c->cartSumSquaredError(vals, result);
00100
00101 if (!grad.empty()) {
00102 double v1[1];
00103 for (uint i=0; i<x.size(); i++) {
00104 double original=vals[i];
00105
00106 vals[i]=original+jump;
00107 c->cartSumSquaredError(vals, v1);
00108
00109 vals[i]=original;
00110 grad[i]=(v1[0]-result[0])/(2.0*jump);
00111 }
00112 }
00113
00114 return result[0];
00115 }
00116
00117
00118 double minfuncL2(const std::vector<double>& x, std::vector<double>& grad, void* data) {
00119
00120
00121
00122
00123
00124 NLOPT_IK *c = (NLOPT_IK *) data;
00125
00126 std::vector<double> vals(x);
00127
00128 double jump=boost::math::tools::epsilon<float>();
00129 double result[1];
00130 c->cartL2NormError(vals, result);
00131
00132 if (!grad.empty()) {
00133 double v1[1];
00134 for (uint i=0; i<x.size(); i++) {
00135 double original=vals[i];
00136
00137 vals[i]=original+jump;
00138 c->cartL2NormError(vals, v1);
00139
00140 vals[i]=original;
00141 grad[i]=(v1[0]-result[0])/(2.0*jump);
00142 }
00143 }
00144
00145 return result[0];
00146 }
00147
00148
00149
00150 void constrainfuncm(uint m, double* result, uint n, const double* x, double* grad, void* data) {
00151
00152
00153
00154
00155 NLOPT_IK *c = (NLOPT_IK *) data;
00156
00157 std::vector<double> vals(n);
00158
00159 for (uint i=0; i<n; i++) {
00160 vals[i]=x[i];
00161 }
00162
00163 double jump=boost::math::tools::epsilon<float>();
00164
00165 c->cartSumSquaredError(vals, result);
00166
00167 if (grad!=NULL) {
00168 std::vector<double> v1(m);
00169 for (uint i=0; i<n; i++) {
00170 double o=vals[i];
00171 vals[i]=o+jump;
00172 c->cartSumSquaredError(vals, v1.data());
00173 vals[i]=o;
00174 for (uint j=0; j<m; j++) {
00175 grad[j*n+i]=(v1[j]-result[j])/(2*jump);
00176 }
00177 }
00178 }
00179 }
00180
00181
00182 NLOPT_IK::NLOPT_IK(const KDL::Chain& _chain, const KDL::JntArray& _q_min, const KDL::JntArray& _q_max, double _maxtime, double _eps, OptType _type):
00183 chain(_chain), fksolver(_chain), maxtime(_maxtime), eps(std::abs(_eps)), TYPE(_type)
00184 {
00185 assert(chain.getNrOfJoints()==_q_min.data.size());
00186 assert(chain.getNrOfJoints()==_q_max.data.size());
00187
00188
00189
00190
00191 reset();
00192
00193 if (chain.getNrOfJoints() < 2) {
00194 ROS_WARN_THROTTLE(1.0,"NLOpt_IK can only be run for chains of length 2 or more");
00195 return;
00196 }
00197 opt = nlopt::opt(nlopt::LD_SLSQP, _chain.getNrOfJoints());
00198
00199 for (uint i=0; i<chain.getNrOfJoints(); i++) {
00200 lb.push_back(_q_min(i));
00201 ub.push_back(_q_max(i));
00202 }
00203
00204 for (uint i=0; i<chain.segments.size(); i++) {
00205 std::string type = chain.segments[i].getJoint().getTypeName();
00206 if (type.find("Rot")!=std::string::npos) {
00207 if (_q_max(types.size())>=std::numeric_limits<float>::max() &&
00208 _q_min(types.size())<=std::numeric_limits<float>::lowest())
00209 types.push_back(KDL::BasicJointType::Continuous);
00210 else
00211 types.push_back(KDL::BasicJointType::RotJoint);
00212 }
00213 else if (type.find("Trans")!=std::string::npos)
00214 types.push_back(KDL::BasicJointType::TransJoint);
00215 }
00216
00217 assert(types.size()==lb.size());
00218
00219 std::vector<double> tolerance(1,boost::math::tools::epsilon<float>());
00220 opt.set_xtol_abs(tolerance[0]);
00221
00222
00223 switch (TYPE) {
00224 case Joint:
00225 opt.set_min_objective(minfunc, this);
00226 opt.add_equality_mconstraint(constrainfuncm, this, tolerance);
00227 break;
00228 case DualQuat:
00229 opt.set_min_objective(minfuncDQ, this);
00230 break;
00231 case SumSq:
00232 opt.set_min_objective(minfuncSumSquared, this);
00233 break;
00234 case L2:
00235 opt.set_min_objective(minfuncL2, this);
00236 break;
00237 }
00238 }
00239
00240
00241 double NLOPT_IK::minJoints(const std::vector<double>& x, std::vector<double>& grad)
00242 {
00243
00244
00245
00246
00247 bool gradient = !grad.empty();
00248
00249 double err = 0;
00250 for (uint i=0; i<x.size(); i++) {
00251 err += pow(x[i] - des[i],2);
00252 if (gradient)
00253 grad[i]=2.0*(x[i]-des[i]);
00254 }
00255
00256 return err;
00257
00258 }
00259
00260
00261 void NLOPT_IK::cartSumSquaredError(const std::vector<double>& x, double error[])
00262 {
00263
00264
00265
00266
00267
00268 if (aborted || progress != -3) {
00269 opt.force_stop();
00270 return;
00271 }
00272
00273
00274 KDL::JntArray q(x.size());
00275
00276 for (uint i=0; i<x.size(); i++)
00277 q(i)=x[i];
00278
00279 int rc = fksolver.JntToCart(q,currentPose);
00280
00281 if (rc < 0)
00282 ROS_FATAL_STREAM("KDL FKSolver is failing: "<<q.data);
00283
00284 if (std::isnan(currentPose.p.x())) {
00285 ROS_ERROR("NaNs from NLOpt!!");
00286 error[0] = std::numeric_limits<float>::max();
00287 progress = -1;
00288 return;
00289 }
00290
00291 KDL::Twist delta_twist = KDL::diffRelative(targetPose,currentPose);
00292
00293 for (int i=0; i<6; i++) {
00294 if (std::abs(delta_twist[i]) <= std::abs(bounds[i]))
00295 delta_twist[i] = 0.0;
00296 }
00297
00298 error[0] = KDL::dot(delta_twist.vel,delta_twist.vel) + KDL::dot(delta_twist.rot,delta_twist.rot);
00299
00300 if (KDL::Equal(delta_twist,KDL::Twist::Zero(),eps)) {
00301 progress=1;
00302 best_x=x;
00303 return;
00304 }
00305 }
00306
00307
00308
00309 void NLOPT_IK::cartL2NormError(const std::vector<double>& x, double error[])
00310 {
00311
00312
00313
00314
00315
00316 if (aborted || progress != -3) {
00317 opt.force_stop();
00318 return;
00319 }
00320
00321 KDL::JntArray q(x.size());
00322
00323 for (uint i=0; i<x.size(); i++)
00324 q(i)=x[i];
00325
00326 int rc = fksolver.JntToCart(q,currentPose);
00327
00328 if (rc < 0)
00329 ROS_FATAL_STREAM("KDL FKSolver is failing: "<<q.data);
00330
00331
00332 if (std::isnan(currentPose.p.x())) {
00333 ROS_ERROR("NaNs from NLOpt!!");
00334 error[0] = std::numeric_limits<float>::max();
00335 progress = -1;
00336 return;
00337 }
00338
00339 KDL::Twist delta_twist = KDL::diffRelative(targetPose,currentPose);
00340
00341 for (int i=0; i<6; i++) {
00342 if (std::abs(delta_twist[i]) <= std::abs(bounds[i]))
00343 delta_twist[i] = 0.0;
00344 }
00345
00346 error[0] = std::sqrt(KDL::dot(delta_twist.vel,delta_twist.vel) + KDL::dot(delta_twist.rot,delta_twist.rot));
00347
00348 if (KDL::Equal(delta_twist,KDL::Twist::Zero(),eps)) {
00349 progress=1;
00350 best_x=x;
00351 return;
00352 }
00353 }
00354
00355
00356
00357
00358 void NLOPT_IK::cartDQError(const std::vector<double>& x, double error[])
00359 {
00360
00361
00362
00363
00364
00365 if (aborted || progress != -3) {
00366 opt.force_stop();
00367 return;
00368 }
00369
00370 KDL::JntArray q(x.size());
00371
00372 for (uint i=0; i<x.size(); i++)
00373 q(i)=x[i];
00374
00375 int rc = fksolver.JntToCart(q,currentPose);
00376
00377 if (rc < 0)
00378 ROS_FATAL_STREAM("KDL FKSolver is failing: "<<q.data);
00379
00380
00381 if (std::isnan(currentPose.p.x())) {
00382 ROS_ERROR("NaNs from NLOpt!!");
00383 error[0] = std::numeric_limits<float>::max();
00384 progress = -1;
00385 return;
00386 }
00387
00388 KDL::Twist delta_twist = KDL::diffRelative(targetPose,currentPose);
00389
00390 for (int i=0; i<6; i++) {
00391 if (std::abs(delta_twist[i]) <= std::abs(bounds[i]))
00392 delta_twist[i] = 0.0;
00393 }
00394
00395 math3d::matrix3x3<double> currentRotationMatrix(currentPose.M.data);
00396 math3d::quaternion<double> currentQuaternion = math3d::rot_matrix_to_quaternion<double>(currentRotationMatrix);
00397 math3d::point3d currentTranslation (currentPose.p.data);
00398 dual_quaternion currentDQ = dual_quaternion::rigid_transformation(currentQuaternion, currentTranslation);
00399
00400 dual_quaternion errorDQ = (currentDQ*!targetDQ).normalize();
00401 errorDQ.log();
00402 error[0] = 4.0f*dot(errorDQ,errorDQ);
00403
00404
00405 if (KDL::Equal(delta_twist,KDL::Twist::Zero(),eps)) {
00406 progress=1;
00407 best_x=x;
00408 return;
00409 }
00410 }
00411
00412
00413 int NLOPT_IK::CartToJnt(const KDL::JntArray &q_init, const KDL::Frame &p_in, KDL::JntArray &q_out, const KDL::Twist _bounds, const KDL::JntArray& q_desired) {
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::local_time();
00424 boost::posix_time::time_duration diff;
00425
00426 bounds = _bounds;
00427 q_out=q_init;
00428
00429 if (chain.getNrOfJoints() < 2) {
00430 ROS_ERROR_THROTTLE(1.0,"NLOpt_IK can only be run for chains of length 2 or more");
00431 return -3;
00432 }
00433
00434 if (q_init.data.size() != types.size()) {
00435 ROS_ERROR_THROTTLE(1.0,"IK seeded with wrong number of joints. Expected %d but got %d",(int)types.size(), (int)q_init.data.size());
00436 return -3;
00437 }
00438
00439 opt.set_maxtime(maxtime);
00440
00441
00442 double minf;
00443
00444 targetPose = p_in;
00445
00446 if (TYPE == 1) {
00447 math3d::matrix3x3<double> targetRotationMatrix(targetPose.M.data);
00448 math3d::quaternion<double> targetQuaternion = math3d::rot_matrix_to_quaternion<double>(targetRotationMatrix);
00449 math3d::point3d targetTranslation (targetPose.p.data);
00450 targetDQ = dual_quaternion::rigid_transformation(targetQuaternion, targetTranslation);
00451 }
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 std::vector<double> x(chain.getNrOfJoints());
00463
00464 for (uint i=0; i < x.size(); i++) {
00465 x[i] = q_init(i);
00466
00467 if (types[i]==KDL::BasicJointType::Continuous)
00468 continue;
00469
00470 if (types[i]==KDL::BasicJointType::TransJoint) {
00471 x[i] = std::min(x[i],ub[i]);
00472 x[i] = std::max(x[i],lb[i]);
00473 }
00474 else {
00475
00476
00477
00478 if (x[i] > ub[i]) {
00479
00480 double diffangle = fmod(x[i]-ub[i],2*M_PI);
00481
00482 x[i] = ub[i] + diffangle - 2*M_PI;
00483 }
00484
00485 if (x[i] < lb[i]) {
00486
00487 double diffangle = fmod(lb[i]-x[i],2*M_PI);
00488
00489 x[i] = lb[i] - diffangle + 2*M_PI;
00490 }
00491
00492 if (x[i] > ub[i])
00493 x[i] = (ub[i]+lb[i])/2.0;
00494 }
00495 }
00496
00497 best_x=x;
00498 progress = -3;
00499
00500 std::vector<double> artificial_lower_limits(lb.size());
00501
00502 for (uint i=0; i< lb.size(); i++)
00503 if (types[i]==KDL::BasicJointType::Continuous)
00504 artificial_lower_limits[i] = best_x[i]-2*M_PI;
00505 else if (types[i]==KDL::BasicJointType::TransJoint)
00506 artificial_lower_limits[i] = lb[i];
00507 else
00508 artificial_lower_limits[i] = std::max(lb[i],best_x[i]-2*M_PI);
00509
00510 opt.set_lower_bounds(artificial_lower_limits);
00511
00512 std::vector<double> artificial_upper_limits(lb.size());
00513
00514 for (uint i=0; i< ub.size(); i++)
00515 if (types[i]==KDL::BasicJointType::Continuous)
00516 artificial_upper_limits[i] = best_x[i]+2*M_PI;
00517 else if (types[i]==KDL::BasicJointType::TransJoint)
00518 artificial_upper_limits[i] = ub[i];
00519 else
00520 artificial_upper_limits[i] = std::min(ub[i],best_x[i]+2*M_PI);
00521
00522 opt.set_upper_bounds(artificial_upper_limits);
00523
00524 if (q_desired.data.size()==0) {
00525 des=x;
00526 }
00527 else
00528 {
00529 des.resize(x.size());
00530 for (uint i=0; i< des.size(); i++)
00531 des[i]=q_desired(i);
00532 }
00533
00534 try {
00535 opt.optimize(x, minf);
00536 } catch (...) {
00537 }
00538
00539 if (progress == -1)
00540 progress = -3;
00541
00542
00543 if (!aborted && progress < 0) {
00544
00545 double time_left;
00546 diff=boost::posix_time::microsec_clock::local_time()-start_time;
00547 time_left = maxtime - diff.total_nanoseconds()/1000000000.0;
00548
00549 while (time_left > 0 && !aborted && progress < 0) {
00550
00551 for (uint i=0; i< x.size(); i++)
00552 x[i]=fRand(artificial_lower_limits[i], artificial_upper_limits[i]);
00553
00554 opt.set_maxtime(time_left);
00555
00556 try
00557 {
00558 opt.optimize(x, minf);
00559 }
00560 catch (...) {}
00561
00562 if (progress == -1)
00563 progress = -3;
00564
00565 diff=boost::posix_time::microsec_clock::local_time()-start_time;
00566 time_left = maxtime - diff.total_nanoseconds()/1000000000.0;
00567 }
00568 }
00569
00570
00571 for (uint i=0; i < x.size(); i++) {
00572 q_out(i) = best_x[i];
00573 }
00574
00575 return progress;
00576
00577 }
00578
00579
00580 }