00001 #if defined(TGT_IS_MANTIS) && defined(TGT_HAS_HEAD)
00002
00003 #include "IKMantis.h"
00004 #include "IKGradientSolver.h"
00005 #include "Kinematics.h"
00006
00007
00008 const std::string IKMantis::autoRegisterIKMantis = IKSolver::getRegistry().registerType<IKMantis>("IKMantis");
00009
00010 IKMantis::IKMantis() {
00011
00012
00013
00014 }
00015
00016 bool IKMantis::solve(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float posPri, const Orientation& oriTgt, float oriPri) const {
00017
00018 bool solved;
00019 if(j.outputOffset == CameraFrameOffset)
00020 solved = solveHead(j,pTgt);
00021 else if(j.outputOffset >= FootFrameOffset+LMdLegOrder && j.outputOffset <= FootFrameOffset+RBkLegOrder)
00022 solved = solvePosLeg(j,pTgt);
00023 else
00024 solved = solveFrontLeg(j,pTgt);
00025 return solved;
00026 }
00027
00028 bool IKMantis::solveHead(KinematicJoint& j, const Position& pTgt) const {
00029
00030 const Point& pTgtPoint = dynamic_cast<const Point&>(pTgt);
00031 KinematicJoint *roll = j.getParent();
00032 KinematicJoint *tilt = roll->getParent();
00033 KinematicJoint *pan = tilt->getParent();
00034 roll->tryQ(0.f);
00035 tilt->tryQ(0.f);
00036
00037
00038
00039
00040
00041 float radius = kine->linkToLink(CameraFrameOffset, HeadOffset+PanOffset)(1,3);
00042 std::cout << " radius = " << radius << std::endl;
00043 fmat::Column<3> targ1 = pan->getFullInvT() * pTgtPoint;
00044 targ1[2] = 0;
00045 float d = targ1.norm();
00046 std::cout << " distance d = " << d << std::endl;
00047 float R = radius/d;
00048 float X = targ1[0] / d;
00049 float Y = targ1[1] / d;
00050 float rsq = sqrt(1 - R*R);
00051 float a = R*X - Y*rsq;
00052 float b = R*Y + X*rsq;
00053 float theta = atan2(-a,b);
00054 float qPan = pan->getQ() + theta;
00055 pan->tryQ(qPan);
00056
00057
00058
00059 radius = kine->linkToLink(CameraFrameOffset, HeadOffset+TiltOffset)(1,3);
00060 fmat::Column<3> targ2 = tilt->getFullInvT() * pTgtPoint;
00061 targ2[2] = 0;
00062 d = targ2.norm();
00063
00064 R = radius/d;
00065 X = targ2[0] / d;
00066 Y = targ2[1] / d;
00067 rsq = sqrt(1 - R*R);
00068 a = R*X - Y*rsq;
00069 b = R*Y + X*rsq;
00070 theta = atan2(-a,b);
00071 float qTilt = tilt->getQ() + theta;
00072 tilt->tryQ(qTilt);
00073
00074
00075
00076
00077
00078 std::cout << "Pan to tilt:" << kine->linkToLink(HeadOffset+PanOffset, HeadOffset+TiltOffset) << std::endl;
00079 return true;
00080 }
00081
00082 bool IKMantis::solvePosLeg(KinematicJoint& j, const Position& pTgt) const {
00083 const Point& pTgtPoint = dynamic_cast<const Point&>(pTgt);
00084 KinematicJoint *knee = j.getParent()->getParent();
00085 KinematicJoint *elevator = knee->getParent();
00086 KinematicJoint *rotor = elevator->getParent();
00087 KinematicJoint *sweep = rotor->getParent();
00088
00089
00090
00091
00092 rotor->tryQ(0.f);
00093
00094 bool solved;
00095
00096 fmat::Column<3> targ1 = sweep->getFullInvT() * pTgtPoint;
00097
00098 float qsweep = atan2(targ1[1],targ1[0]) + sweep->getQ();
00099 sweep->tryQ(qsweep);
00100
00101
00102
00103 fmat::Column<3> targ2 = elevator->getFullInvT() * pTgtPoint;
00104
00105
00106 fmat::Column<3> elvtrPos = elevator->getWorldPosition();
00107 fmat::Column<3> len1 = knee->getFullInvT() * elvtrPos;
00108 fmat::Column<3> footframe = j.getWorldPosition();
00109 fmat::Column<3> len2 = knee->getFullInvT() * footframe;
00110
00111
00112
00113 float L1 = hypotf(len1[0],len1[1]);
00114 float L2 = hypotf(len2[0],len2[1]);
00115 float qknee;
00116 float qelevtr;
00117
00118
00119
00120 float t2angle = atan2(targ2[1],targ2[0]);
00121 float k_cos = (targ2[0]*targ2[0] + targ2[1]*targ2[1] - L1*L1 - L2*L2) / (2*L1*L2);
00122 float k_sin = std::sqrt(1 - k_cos*k_cos) * (t2angle > 0.0 ? 1 : -1);
00123 float k1 = L1 + k_cos*L2;
00124 float k2 = k_sin*L2;
00125
00126
00127 float alpha = atan2(len2[1],len2[0]);
00128
00129
00130 if (L1 + L2 <= hypotf(targ2[0],targ2[1])) {
00131
00132 qknee = -alpha;
00133 qelevtr = t2angle + elevator->getQ();
00134 solved = false;
00135
00136 } else {
00137 qknee = atan2(k_sin,k_cos) - alpha ;
00138 qelevtr = t2angle - atan2(k2,k1) + elevator->getQ();
00139
00140 solved = true;
00141 }
00142
00143
00144
00145
00146 elevator->tryQ(qelevtr);
00147 knee->tryQ(qknee);
00148
00149 return solved;
00150 }
00151
00152 bool IKMantis::solveFrontLeg(KinematicJoint& j, const Position& pTgt) const {
00153 const Point& pTgtPoint = dynamic_cast<const Point&>(pTgt);
00154 bool solved;
00155 KinematicJoint *wrist = j.getParent()->getParent();
00156 KinematicJoint *twist2 = wrist->getParent();
00157 KinematicJoint *elbow = twist2->getParent();
00158 KinematicJoint *twist1 = elbow->getParent();
00159 KinematicJoint *elevator = twist1->getParent();
00160 KinematicJoint *sweep = elevator->getParent();
00161
00162 twist1->tryQ(0);
00163
00164
00165
00166
00167 fmat::Column<3> footframe = j.getWorldPosition();
00168 fmat::Column<3> footToWrist = wrist->getFullInvT() * footframe;
00169 float len_tibia = hypotf(footToWrist[0],footToWrist[1]);
00170
00171 const Point pTgtWrist = pTgtPoint;
00172 pTgtWrist.z = pTgtPoint.z + len_tibia;
00173
00174
00175
00176 fmat::Column<3> targ1 = sweep->getFullInvT() * pTgtWrist;
00177
00178
00179 float qsweep = atan2(targ1[1],targ1[0]) + sweep->getQ();
00180 sweep->tryQ(qsweep);
00181
00182
00183
00184 fmat::Column<3> targ2 = elevator->getFullInvT() * pTgtWrist;
00185
00186 fmat::Column<3> elvtrPos = elevator->getWorldPosition();
00187 fmat::Column<3> len1 = elbow->getFullInvT() * elvtrPos;
00188 fmat::Column<3> wristPos = wrist->getWorldPosition();
00189 fmat::Column<3> len2 = elbow->getFullInvT() * wristPos;
00190
00191
00192
00193 float L1 = hypotf(len1[0],len1[1]);
00194 float L2 = hypotf(len2[0],len2[1]);
00195 float qelevtr;
00196 float qelbow;
00197
00198
00199
00200 float k_cos = (targ2[0]*targ2[0] + targ2[1]*targ2[1] - L1*L1 - L2*L2) / (2*L1*L2);
00201 float k_sin = std::sqrt(1 - k_cos*k_cos);
00202 if (j.outputOffset == FootFrameOffset+LFrLegOrder) k_sin = -k_sin;
00203 float k1 = L1 + k_cos*L2;
00204 float k2 = k_sin*L2;
00205
00206 if (L1 + L2 <= hypotf(targ2[0],targ2[1])) {
00207
00208 qelbow = 0;
00209 qelevtr = atan2(targ2[1],targ2[0]) + elevator->getQ();
00210 std::cout << "Point too far away " << std::endl;
00211 solved = false;
00212 } else {
00213 qelbow = atan2(k_sin,k_cos) ;
00214 qelevtr = atan2(targ2[1],targ2[0]) - atan2(k2,k1) + elevator->getQ();
00215 solved = true;
00216 }
00217
00218
00219
00220
00221 elevator->tryQ(qelevtr);
00222 elbow->tryQ(qelbow);
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 fmat::Column<3> targ3 = twist2->getFullInvT() * pTgtPoint;
00238 float qtwist2;
00239
00240 if (j.outputOffset == FootFrameOffset+LFrLegOrder) qtwist2 = -atan2(-targ3[0], -targ3[1]) + twist2->getQ();
00241 else qtwist2 = -atan2(targ3[0], targ3[1]) + twist2->getQ();
00242
00243
00244 twist2->tryQ(qtwist2);
00245
00246
00247
00248 float beta = atan2(footToWrist[1],footToWrist[0]);
00249
00250 fmat::Column<3> targ4 = wrist->getFullInvT() * pTgtPoint;
00251
00252 float qwrist = atan2(targ4[1],targ4[0]) - beta + wrist->getQ();
00253
00254 wrist->tryQ(qwrist);
00255
00256
00257
00258
00259
00260 return solved;
00261 }
00262
00263 IKSolver::StepResult_t IKMantis::step(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float pDist, float posPri, const Orientation& oriTgt, float oriDist, float oriPri) const {
00264
00265 fmat::Transform Tj = j.getFullT();
00266 fmat::Column<3> pEffBase(Tj*pEff);
00267 fmat::Quaternion qj = j.getWorldQuaternion();
00268 Rotation oEffBase = qj*oriEff;
00269 Point de;
00270 pTgt.computeErrorGradient(pEffBase,oEffBase,de);
00271
00272 StepResult_t res=SUCCESS;
00273 if(de.norm()>pDist) {
00274 de*=pDist/de.norm();
00275 res = PROGRESS;
00276 }
00277 Point pTgtP = pEffBase+de;
00278 if(solve(pEff,oriEff,j,pTgtP,posPri,oriTgt,oriPri))
00279 return res;
00280 return LIMITS;
00281 }
00282
00283 #endif