00001 #include "IKGradientSolver.h"
00002 #include "Shared/fmat.h"
00003 #include <cmath>
00004 #include <valarray>
00005
00006 using namespace std;
00007
00008 const std::string IKGradientSolver::autoRegisterIKGradientSolver = IKSolver::getRegistry().registerType<IKGradientSolver>("IKGradientSolver");
00009 const std::string IKGradientSolver::autoRegisterDefaultIKSolver = IKSolver::getRegistry().registerType<IKGradientSolver>("");
00010
00011 bool IKGradientSolver::solve(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float posPri, const Orientation& oriTgt, float oriPri) const {
00012 if(posPri==0 && oriPri==0)
00013 return true;
00014
00015 posPri=std::max(0.f,posPri);
00016 oriPri=std::max(0.f,oriPri);
00017
00018 KinematicJoint* firstMobileJoint = NULL;
00019 for(KinematicJoint * ancestor = &j; ancestor!=NULL; ancestor = ancestor->getParent())
00020 if(ancestor->isMobile())
00021 firstMobileJoint = ancestor;
00022 if(firstMobileJoint==NULL)
00023 return false;
00024
00025
00026 fmat::Transform Tj = j.getT(*firstMobileJoint);
00027 fmat::Column<3> pEffFMJ(Tj*pEff);
00028 fmat::fmatReal pDist = pEffFMJ.norm()/10;
00029
00030
00031 fmat::fmatReal oriDist = 1;
00032
00033 std::valarray<fmat::fmatReal> q(j.getDepth()+1);
00034 for(KinematicJoint * ancestor = &j; ancestor!=NULL; ancestor = ancestor->getParent())
00035 q[ancestor->getDepth()] = ancestor->getQ();
00036 std::valarray<fmat::fmatReal> dq, ndq(j.getDepth()+1);
00037 unsigned int iterCnt=0, overCnt=0;
00038 bool solved=false;
00039 while(iterCnt<MAX_ITER) {
00040 IKSolver::StepResult_t res = step(pEff,oriEff,j,pTgt,pDist,posPri,oriTgt,oriDist,oriPri,false);
00041 if(res==SUCCESS) {
00042 solved=true;
00043 break;
00044 }
00045 if(res!=PROGRESS) {
00046
00047 break;
00048 }
00049 for(KinematicJoint * ancestor = &j; ancestor!=NULL; ancestor = ancestor->getParent()) {
00050 ndq[ancestor->getDepth()] = ancestor->getQ() - q[ancestor->getDepth()];
00051 q[ancestor->getDepth()] = ancestor->getQ();
00052 }
00053 fmat::fmatReal qa=1;
00054 if(dq.size()==0) {
00055 dq.resize(j.getDepth()+1);
00056 dq=ndq;
00057 } else {
00058 qa = (dq*ndq).sum();
00059 std::swap(dq,ndq);
00060 }
00061 if(std::max(std::abs(dq.max()),std::abs(dq.min())) < QTOL) {
00062
00063 break;
00064 }
00065 if(qa<0) {
00066
00067 pDist *= .75f;
00068 oriDist *= .75f;
00069 ++overCnt;
00070 }
00071
00072
00073
00074
00075 ++iterCnt;
00076 }
00077
00078 return solved;
00079 }
00080
00081 IKSolver::StepResult_t IKGradientSolver::step(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float pDist, float posPri, const Orientation& oriTgt, float oriDist, float oriPri, bool successInReach) const {
00082 if((posPri<=0 && oriPri<=0) || (pDist<=0 && oriDist<=0))
00083 return SUCCESS;
00084
00085 posPri=std::max(0.f,posPri);
00086 oriPri=std::max(0.f,oriPri);
00087 pDist=std::max(0.f,pDist);
00088 oriDist=std::max(0.f,oriDist);
00089
00090 const float totPri = posPri+oriPri;
00091 posPri/=totPri;
00092 oriPri/=totPri;
00093
00094
00095 StepResult_t result = LIMITS;
00096
00097
00098 std::vector<int> mobile;
00099 mobile.reserve(j.getDepth()+1);
00100 for(KinematicJoint * ancestor=&j; ancestor!=NULL; ancestor=ancestor->getParent()) {
00101 if(ancestor->isMobile())
00102 mobile.push_back(ancestor->getDepth());
00103
00104
00105 }
00106 std::reverse(mobile.begin(),mobile.end());
00107
00108
00109 fmat::fmatReal distRemain = pDist;
00110 fmat::fmatReal angRemain = oriDist;
00111
00112 while(mobile.size()>0) {
00113
00114 fmat::Transform Tj = j.getFullT();
00115 fmat::Column<3> pEffBase(Tj*pEff);
00116 fmat::Quaternion qj = j.getWorldQuaternion();
00117 Rotation oEffBase = qj*oriEff;
00118
00119 fmat::Column<3> pErr;
00120 pTgt.computeErrorGradient(pEffBase,oEffBase,pErr);
00121
00122 fmat::Quaternion oriErr;
00123 oriTgt.computeErrorGradient(pEffBase,oEffBase,oriErr);
00124 oriErr.normalize();
00125
00126 fmat::fmatReal pErrMagnitude = pErr.norm();
00127 fmat::fmatReal oriErrMagnitude = std::abs(oriErr.angle());
00128
00129
00130 if(pErrMagnitude/distRemain*posPri < .001 && oriErrMagnitude/angRemain*oriPri < .001) {
00131
00132 return SUCCESS;
00133 }
00134 if(pErrMagnitude*posPri < PTOL && oriErrMagnitude*oriPri < OTOL) {
00135
00136 return SUCCESS;
00137 }
00138 if(pErrMagnitude<distRemain && oriErrMagnitude<angRemain) {
00139 distRemain=pErrMagnitude;
00140 angRemain=oriErrMagnitude;
00141 if(successInReach)
00142 result = SUCCESS;
00143 } else if(pErrMagnitude<distRemain) {
00144 distRemain=pErrMagnitude;
00145 if(oriPri==0 && successInReach)
00146 result = SUCCESS;
00147 } else if(oriErrMagnitude<angRemain) {
00148 angRemain=oriErrMagnitude;
00149 if(posPri==0 && successInReach)
00150 result = SUCCESS;
00151 }
00152
00153 std::vector<fmat::Column<6> > J;
00154 j.getFullJacobian(pEffBase,J);
00155
00156 std::vector<fmat::Column<6> > Jm(mobile.size());
00157 for(size_t i=0; i<mobile.size(); ++i)
00158 Jm[i] = J[mobile[i]];
00159
00160
00161 std::valarray<fmat::fmatReal> q(mobile.size());
00162
00163 if(posPri>0 && distRemain>0) {
00164
00165
00166
00167
00168
00169
00170
00171 std::valarray<fmat::fmatReal> posQ(Jm.size());
00172 for(unsigned int i=0; i<posQ.size(); ++i) {
00173 posQ[i]=fmat::dotProduct(fmat::SubVector<3>(Jm[i]),pErr);
00174 }
00175
00176
00177
00178
00179 fmat::Column<3> move;
00180 for(unsigned int i=0; i<posQ.size(); ++i)
00181 move+=fmat::SubVector<3>(Jm[i])*posQ[i];
00182
00183 fmat::fmatReal moveSize = move.norm();
00184 if(moveSize > std::numeric_limits<float>::epsilon())
00185 posQ *= distRemain / moveSize;
00186
00187
00188 if(oriErrMagnitude*oriPri < OTOL) {
00189
00190
00191 fmat::fmatReal moveCos = fmat::dotProduct(pErr/pErrMagnitude, move/moveSize);
00192 if(moveCos < QTOL) {
00193
00194 return RANGE;
00195 }
00196
00197
00198 fmat::fmatReal posqsum=0;
00199 for(unsigned int i=0; i<posQ.size(); ++i)
00200 posqsum+=posQ[i]*posQ[i];
00201 if(std::sqrt(posqsum) < std::numeric_limits<float>::epsilon()) {
00202
00203 return RANGE;
00204 }
00205 }
00206
00207
00208 posQ*=posPri;
00209 q += posQ;
00210 }
00211
00212 if(oriPri>0 && angRemain>0) {
00213
00214 std::valarray<fmat::fmatReal> oriQ(Jm.size());
00215 fmat::Column<3> oriErrV = oriErr.axis();
00216
00217 for(unsigned int i=0; i<oriQ.size(); ++i) {
00218 oriQ[i] = fmat::dotProduct(fmat::SubVector<3>(Jm[i],3),oriErrV);
00219
00220 }
00221
00222
00223 fmat::fmatReal rotSize=0;
00224 for(unsigned int i=0; i<oriQ.size(); ++i)
00225 rotSize+=oriQ[i]*oriQ[i];
00226 rotSize=std::sqrt(rotSize);
00227
00228
00229
00230 if(rotSize > std::numeric_limits<float>::epsilon())
00231 oriQ *= oriDist * angRemain / rotSize;
00232
00233
00234 oriQ*=oriPri;
00235 q += oriQ;
00236 }
00237
00238
00239 size_t prevSize=mobile.size();
00240 KinematicJoint * ancestor=&j;
00241 for(int i=mobile.size()-1; i>=0; --i) {
00242 while(ancestor!=NULL && ancestor->getDepth()>static_cast<typeof(ancestor->getDepth())>(mobile[i]))
00243 ancestor=ancestor->getParent();
00244 q[i]+=ancestor->getQ();
00245 if(!ancestor->validQ(q[i])) {
00246
00247
00248 ancestor->tryQ(q[i]);
00249 std::vector<int>::iterator it=mobile.begin();
00250 std::advance(it,i);
00251 mobile.erase(it);
00252 }
00253 }
00254 if(mobile.size()<prevSize) {
00255
00256 fmat::Column<3> newpEffBase(j.getFullT()*pEff);
00257 distRemain -= (newpEffBase - pEffBase).norm();
00258
00259 fmat::Quaternion newoEffBase = j.getWorldQuaternion()*oriEff;
00260 fmat::Quaternion angMoved = crossProduct(newoEffBase, oEffBase);
00261
00262 angRemain -= std::abs(angMoved.angle());
00263
00264
00265 if(angRemain<=0 && distRemain<=0)
00266 return PROGRESS;
00267 if(distRemain<std::numeric_limits<float>::epsilon())
00268 distRemain=std::numeric_limits<float>::epsilon();
00269 if(angRemain<std::numeric_limits<float>::epsilon())
00270 angRemain=std::numeric_limits<float>::epsilon();
00271 } else {
00272
00273 ancestor=&j;
00274 for(int i=mobile.size()-1; i>=0; --i) {
00275 while(ancestor!=NULL && ancestor->getDepth()>static_cast<typeof(ancestor->getDepth())>(mobile[i]))
00276 ancestor=ancestor->getParent();
00277 ancestor->setQ(q[i]);
00278 }
00279 return (result==LIMITS) ? PROGRESS : result;
00280 }
00281 }
00282 return result;
00283 }
00284
00285
00286
00287
00288