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 #include <robot/control/kinematics/IKOR>
00026
00027 #include <robot/control/kinematics/solution_error>
00028 #include <robot/control/kinematics/SVDFullSpaceSolver>
00029 #include <robot/control/kinematics/Optimizer>
00030 #include <robot/control/kinematics/ReferenceOpVectorFormObjective>
00031 #include <robot/control/kinematics/AnalyticLagrangianFSBetaOptimizer>
00032 #include <robot/control/kinematics/AnalyticLagrangianNullSpaceBetaOptimizer>
00033
00034
00035 using robot::control::kinematics::IKOR;
00036
00037 using base::Vector;
00038 using base::Orient;
00039 using base::dot;
00040 using robot::control::kinematics::SVDFullSpaceSolver;
00041 using robot::control::kinematics::ReferenceOpVectorFormObjective;
00042 using robot::control::kinematics::BetaFormConstraints;
00043 using robot::control::kinematics::AnalyticLagrangianFSBetaOptimizer;
00044 using robot::control::kinematics::AnalyticLagrangianNullSpaceBetaOptimizer;
00045
00046
00047 const Real small = 5.0e-05;
00048
00049
00050 IKOR::IKOR(const robot::KinematicChain& chain, const Vector& jointWeights,
00051 bool nonHolonomicPlatformActive, Real platformL)
00052 : chain(chain), weights(jointWeights),
00053 nonHolonomicPlatformActive(nonHolonomicPlatformActive), L(platformL)
00054 {
00055 if (weights.size() == 0) {
00056 weights.reset(Vector(chain.dof()));
00057 for(Int i=0; i<weights.size(); i++) weights[i]=1.0;
00058 }
00059
00060 solver = ref<SVDFullSpaceSolver>(NewObj SVDFullSpaceSolver());
00061 }
00062
00063
00064
00065 bool IKOR::isConstraintTypeSupported(OptimizationConstraint optConstraint,
00066 OptimizationMethod optMethod,
00067 OptimizationCriterion optCriterion)
00068 {
00069 if (optMethod==DefaultMethod) optMethod=Lagrangian;
00070 if (optCriterion==DefaultCriterion) optCriterion=LeastNorm;
00071
00072 if (optMethod == Lagrangian) {
00073
00074 if (optCriterion == LeastNorm) {
00075
00076 return ( (optConstraint == JointLimits)
00077 || (optConstraint == ObstacleAvoidance) );
00078
00079 }
00080
00081 }
00082
00083 return false;
00084 }
00085
00086
00087 Vector IKOR::solve(const Vector& dx, const Vector& x, const Vector& q,
00088 const base::Matrix& J,
00089 OptimizationMethod optMethod,
00090 OptimizationCriterion optCriterion,
00091 OptimizationConstraints optConstraints,
00092 base::Orient::Representation orientationRepresentation)
00093 {
00094 if (optMethod==DefaultMethod) optMethod=Lagrangian;
00095 if (optCriterion==DefaultCriterion) optCriterion=LeastNorm;
00096 if (optConstraints.test(DefaultConstraints)) optConstraints.reset();
00097
00098 const Int N = J.size1();
00099 const Int M = J.size2();
00100
00101 Assert(dx.size() == x.size());
00102 Assert(q.size() == M);
00103
00104
00105
00106 Vector newdx;
00107 if (N>3) {
00108 Vector dpos(3);
00109 dpos = vectorRange(dx,Range(0,3));
00110 Orient orient(vectorRange(x,Range(3,x.size())),orientationRepresentation);
00111 Orient dorient(vectorRange(dx,Range(3,dx.size())),orientationRepresentation);
00112 Vector omega(3);
00113 omega = orient.getBinv()*Vector(dorient);
00114 newdx.resize(6);
00115 vectorRange(newdx,Range(0,3)) = dpos;
00116 vectorRange(newdx,Range(3,6)) = omega;
00117 }
00118 else
00119 newdx.reset(dx);
00120
00121 Assert(newdx.size() == N);
00122
00123 bool nullSpaceMotion = base::equals(dx,zeroVector(N),small);
00124
00125
00126
00127 array<Int> dependentRowsEliminated;
00128 const Vector& b(newdx);
00129 Matrix gs;
00130 try {
00131 gs = solver->solve(J, b, dependentRowsEliminated);
00132 } catch (std::exception& e) {
00133 throw solution_error(Exception(String("Unable to generate solution space for the given dx in the current state (impossible motion?) - FSP failed:")+e.what()));
00134 }
00135
00136
00137
00138 ref<Optimizer> optimizer;
00139 ref<Optimizer::Objective> objective;
00140 ref<Optimizer::Constraints> constraints;
00141
00142 ref<LagrangianOptimizer> lagOptimizer;
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 if (optMethod==Lagrangian) {
00155
00156
00157
00158 Matrix B(M,M);
00159 Vector dZr(M);
00160
00161 switch (optCriterion) {
00162 case LeastNorm: weightedLeastNorm(B,dZr, weights); break;
00163 case LeastFlow: throw std::runtime_error(Exception("LeastFlow criteria not implemented for Larganrian method."));
00164 default:
00165 throw std::invalid_argument(Exception("unsupported/unknown criteria for Largangian Method"));
00166 }
00167
00168 ref<ReferenceOpVectorFormObjective> rovfObjective(NewObj ReferenceOpVectorFormObjective());
00169 objective = rovfObjective;
00170 rovfObjective->setB(B);
00171 rovfObjective->setdZr(dZr);
00172
00173
00174
00175 ref<BetaFormConstraints> betaconstraints(NewObj BetaFormConstraints());
00176 constraints = betaconstraints;
00177 betaconstraints->clear();
00178
00179 if (nonHolonomicPlatformActive)
00180 addNonholonomicConstraint(gs, q, betaconstraints);
00181
00182
00183 if (dependentRowsEliminated.size() > 0)
00184 addDependentRowConstraints(dependentRowsEliminated, gs, J, b, betaconstraints);
00185
00186
00187
00188 if (!nullSpaceMotion)
00189 lagOptimizer = ref<AnalyticLagrangianFSBetaOptimizer>(NewObj AnalyticLagrangianFSBetaOptimizer());
00190 else
00191 lagOptimizer = ref<AnalyticLagrangianNullSpaceBetaOptimizer>(NewObj AnalyticLagrangianNullSpaceBetaOptimizer());
00192 lagOptimizer->setGs(gs);
00193 optimizer = lagOptimizer;
00194
00195 }
00196 else
00197 throw std::invalid_argument(Exception("unimplemented optimization method"));
00198
00199
00200
00201
00202 Vector dq(M);
00203
00204 try {
00205
00206 dq = optimizer->optimize(objective, constraints);
00207
00208 } catch (solution_error& e) {
00209 dq = zeroVector(M);
00210 throw solution_error(Exception(String("Unable to solve for the given dx in the current state - optimization failed:")+e.what()),e);
00211 }
00212
00213
00214
00215
00216
00217 Int numConstraints;
00218 do {
00219 numConstraints = constraints->numConstraints();
00220
00221
00222
00223
00224 if (optMethod == Lagrangian) {
00225
00226 ref<BetaFormConstraints> betaconstraints(narrow_ref<BetaFormConstraints>(constraints));
00227
00228
00229 betaconstraints->clear();
00230 if (nonHolonomicPlatformActive)
00231 addNonholonomicConstraint(gs, q, betaconstraints);
00232 if (dependentRowsEliminated.size() > 0)
00233 addDependentRowConstraints(dependentRowsEliminated, gs, J, b, betaconstraints);
00234
00235
00236
00237 if (optConstraints.test(JointLimits)) {
00238 addJointLimitConstraints(gs, q, dq, betaconstraints);
00239 }
00240
00241 if (optConstraints.test(ObstacleAvoidance))
00242 addObstacleAvoidanceConstraints(gs, q, dq, betaconstraints);
00243
00244 }
00245 else
00246 throw std::invalid_argument(Exception("unimplemented optimization method"));
00247
00248
00249 if ( constraints->numConstraints() > numConstraints) {
00250
00251
00252 try {
00253 Debugcln(DJ,"optimizing2:");
00254 Debugcln(DJ,"constraints:\n" << *constraints);
00255 Debugcln(DJ," extra constraints:" << (constraints->numConstraints()-numConstraints));
00256 dq = optimizer->optimize(objective, constraints);
00257
00258 } catch (solution_error& e) {
00259 dq = zeroVector(M);
00260 throw solution_error(Exception(String("Unable to solve for the given dx in the current state - optimization failed:")+e.what()),e);
00261 }
00262
00263 }
00264
00265
00266 } while ( constraints->numConstraints() > numConstraints);
00267
00268
00269 return dq;
00270 }
00271
00272
00273 void IKOR::setProximitySensorData(const array<LinkProximityData>& proximityData, Real d)
00274 {
00275 proximitySensorData = proximityData;
00276 this->d = d;
00277 }
00278
00279
00280
00281 void IKOR::setParameter(const String& name, Real value)
00282 {
00283 throw std::invalid_argument(Exception("unknown parameter name"));
00284 }
00285
00286
00287
00288 void IKOR::weightedLeastNorm(Matrix& B, Vector& dZr, Vector weights)
00289 {
00290
00291 dZr = zeroVector(dZr.size());
00292
00293
00294 for(Int j=0; j<B.size2(); j++)
00295 for(Int i=0; i<B.size1(); i++)
00296 B(i,j) = (i!=j)?0:weights[i];
00297 }
00298
00299
00300 IKOR::RankLossBetaConstraint::RankLossBetaConstraint(Int row, const Matrix& A, const Vector& b, const Matrix& gs)
00301 : row(row)
00302 {
00303 setName(className());
00304
00305 const Int span=gs.size2();
00306 beta.resize(span);
00307 Vector Ar(matrixRow(A,row));
00308
00309 for(Int i=0; i<span; i++)
00310 beta[i] = dot(Ar, matrixRow(gs,i) ) / b[row];
00311
00312 }
00313
00314
00315 void IKOR::addDependentRowConstraints(const array<Int>& rows, const Matrix& gs, const Matrix& A, const Vector& b, ref<BetaFormConstraints> constraints)
00316 {
00317
00318 for(Int i=0; i<rows.size(); i++)
00319 constraints->addConstraint(ref<BetaFormConstraints::BetaFormConstraint>(NewObj RankLossBetaConstraint(rows[i], A, b, gs)) );
00320 }
00321
00322
00323
00324
00325 void IKOR::addJointLimitConstraints(const Matrix& gs, const Vector& q, const Vector& dq, ref<BetaFormConstraints> constraints)
00326 {
00327
00328
00329 const Int M = gs.size1();
00330 Vector tq(q+dq);
00331
00332 for(Int v=0; v<M; v++) {
00333
00334
00335 Real minValue = chain.variableMinLimit(v);
00336 Real maxValue = chain.variableMaxLimit(v);
00337 bool hasMinLimit = true;
00338 bool hasMaxLimit = true;
00339 if (chain.variableUnitType(v)==KinematicChain::Angle) {
00340 if ( (Math::equals(minValue, KinematicChain::unboundedMinAngleLimit))
00341 ||(Math::equals(maxValue, KinematicChain::unboundedMaxAngleLimit)) ) {
00342 hasMinLimit = hasMaxLimit = false;
00343 }
00344 }
00345 else {
00346 if (Math::equals(minValue, KinematicChain::unboundedMinDistLimit,999))
00347 hasMinLimit = false;
00348 if (Math::equals(maxValue, KinematicChain::unboundedMaxDistLimit,999))
00349 hasMaxLimit = false;
00350 }
00351
00352
00353 if (hasMinLimit && (tq[v] < minValue)) {
00354 Debugcln(IKOR,"v:" << v << " m" << Math::radToDeg(minValue) << " > " << Math::radToDeg(tq[v]) );
00355 constraints->addConstraint(
00356 ref<BetaFormConstraints::BetaFormConstraint>(NewObj JointLimitBetaConstraint(v,minValue-tq[v],gs))
00357 );
00358 }
00359
00360 if (hasMaxLimit && (tq[v] > maxValue)) {
00361 Debugcln(IKOR,"v:" << v << " m" << Math::radToDeg(maxValue) << " < " << Math::radToDeg(tq[v]) );
00362 constraints->addConstraint(
00363 ref<BetaFormConstraints::BetaFormConstraint>(NewObj JointLimitBetaConstraint(v,maxValue-tq[v],gs))
00364 );
00365 }
00366
00367 }
00368
00369 }
00370
00371
00372
00373 void IKOR::addNonholonomicConstraint(const Matrix& gs, const Vector& q, ref<BetaFormConstraints> constraints)
00374 {
00375
00376
00377
00378 Vector alpha(gs.size2());
00379
00380 Real sqm = Math::sin(q[2]);
00381 Real cqm = Math::cos(q[2]);
00382 for(Int i=0; i<gs.size2(); i++) {
00383 Vector gi( matrixColumn(gs,i) );
00384 alpha[i] = -sqm*gi[0] + cqm*gi[1] - L*gi[2];
00385 }
00386
00387 constraints->setAlphaConstraint(alpha);
00388 }
00389
00390
00391
00392
00393 IKOR::PushAwayBetaConstraint::PushAwayBetaConstraint(Int v, Real Xvx,
00394 const Vector& n, Real L,
00395 const Matrix& gs,
00396 const robot::KinematicChain& chain, const Vector& q)
00397 : v(v), Xvx(Xvx), n(n), L(L)
00398 {
00399 setName(className());
00400
00401
00402
00403
00404
00405 Int l = chain.linkIndexOfVariable(v);
00406 KinematicChain chainX;
00407 for(Int li=0; li<l-1; li++)
00408 chainX += chain[li];
00409
00410
00411
00412
00413 KinematicChain::Link ll(chain[l]);
00414 Assertm(ll.isDHType() && Math::equals(ll.getD(),0), "is DH link & d==0 (current impl. can't handle general case)");
00415 ll.setA(Xvx);
00416 chainX += ll;
00417
00418 Vector ql( chainX.dof() );
00419 ql = vectorRange( q, Range(0,ql.size() ) );
00420
00421
00422
00423
00424
00425
00426
00427 Matrix JXq( chainX.getJacobian( ql, false ) );
00428
00429 const Int span=gs.size2();
00430 Int m( ql.size() );
00431 beta.resize(span);
00432
00433
00434 for(Int k=0; k<span; k++) {
00435 beta[k] = 0;
00436 Vector gk( matrixColumn(gs, k) );
00437 for(Int i=0; i<3; i++) {
00438 for(Int j=0; j<m; j++) {
00439
00440
00441
00442 beta[k] += JXq(i,j) * gk[j] * n[i];
00443
00444 }
00445 }
00446 beta[k] /= L;
00447 }
00448
00449 }
00450
00451
00452
00453
00454 void IKOR::addObstacleAvoidanceConstraints(const Matrix& gs, const Vector& q, const Vector& dq, ref<BetaFormConstraints> constraints)
00455 {
00456 if (proximitySensorData.size() == 0) return;
00457
00458
00459 Assert( proximitySensorData.size() == chain.dof() );
00460
00461
00462 for(Int v=0; v<chain.dof(); v++) {
00463
00464 LinkProximityData& pd( proximitySensorData[v] );
00465
00466 if (pd.distance < d) {
00467 if (!pd.direction.equals( zeroVector(3) )) {
00468
00469 Real L = d - pd.distance + 1e-4;
00470 Vector n( -pd.direction );
00471
00472
00473
00474
00475
00476 if ( Math::equals(pd.intercept,0) && (chain.linkIndexOfVariable(v) > 0) ) {
00477 if ( chain[chain.linkIndexOfVariable(v)].type() == KinematicChain::Link::Revolute )
00478 return;
00479 }
00480
00481 Debugln(DJ,"proximity: variable " << v << " (l=" << chain.linkIndexOfVariable(v) << "):\nL=" << L << " n=" << n << " lXj=" << pd.intercept << " d=" << d << " dist=" << pd.distance);
00482 constraints->addConstraint(ref<BetaFormConstraints::BetaFormConstraint>(NewObj PushAwayBetaConstraint(v,pd.intercept, n, L, gs, chain, q)) );
00483 }
00484
00485 }
00486
00487 }
00488
00489 }
00490
00491