00001 #if defined(TGT_IS_CALLIOPE) && defined(TGT_HAS_ARMS)
00002
00003 #include "IKCalliope.h"
00004 #include "Kinematics.h"
00005
00006 const float IKCalliope::EPSILON = std::numeric_limits<float>::min();
00007 const std::string IKCalliope::autoRegisterIKCalliope = IKSolver::getRegistry().registerType<IKCalliope>("IKCalliope");
00008
00009 # if defined(TGT_IS_CALLIOPE5)
00010
00011 IKCalliope::IKCalliope() : L1(), L2(), jointLimits() {
00012 const KinematicJoint* j = kine->getKinematicJoint(ArmWristOffset);
00013 if ( j == NULL )
00014 throw std::runtime_error("IKCalliope can't find GripperFrameOffset or ARM:wristrot");
00015
00016 L1 = j->getParent()->r;
00017 L2 = j->r;
00018 jointLimits[0][0] = j->getParent()->getParent()->qmin;
00019 jointLimits[0][1] = j->getParent()->getParent()->qmax;
00020 jointLimits[1][0] = j->getParent()->qmin;
00021 jointLimits[1][1] = j->getParent()->qmax;
00022 jointLimits[2][0] = j->qmin;
00023 jointLimits[2][1] = j->qmax;
00024 }
00025
00026 bool IKCalliope::solve(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float posPri, const Orientation& oriTgt, float oriPri) const {
00027
00028 const Point& pTgtPoint = dynamic_cast<const Point&>(pTgt);
00029 Point pTgtBase(kine->getKinematicJoint(ArmBaseOffset)->getTo().inverse() * pTgtPoint);
00030
00031
00032 float qBase = std::atan2(pTgtBase.y, pTgtBase.x);
00033 float qOffset = kine->getKinematicJoint(ArmBaseOffset)->qOffset;
00034 fmat::SubVector<2> gripperToBase(kine->linkToLink(GripperFrameOffset, ArmBaseOffset).translation());
00035 fmat::SubVector<2> wristToBase(kine->linkToLink(ArmWristOffset, ArmBaseOffset).translation());
00036 float qGripper = fmat::atan(gripperToBase) - fmat::atan(wristToBase);
00037 j.getParent()->getParent()->getParent()->getParent()->getParent()->setQ(qBase-qOffset-qGripper);
00038
00039
00040 fmat::Column<2> pTgtV;
00041 if (std::abs(std::cos(qBase)) < EPSILON)
00042 pTgtV[0] = pTgtBase.y;
00043 else
00044 pTgtV[0] = pTgtBase.x / std::cos(qBase);
00045 pTgtV[1] = pTgtBase.z;
00046
00047 float baseToShoulder = kine->linkToLink(ArmShoulderOffset, ArmBaseOffset).translation()[0];
00048 pTgtV[0] -= baseToShoulder;
00049
00050 const Rotation& oriTgtV = dynamic_cast<const Rotation&>(oriTgt);
00051
00052
00053 IKCalliope::Solutions sols = closestThreeLinkIK(pTgtV, pEff, oriTgtV.axisComponent(fmat::UNIT3_Y));
00054
00055
00056 j.getParent()->setQ(oriTgtV.axisComponent(fmat::UNIT3_Z));
00057
00058
00059 j.getParent()->getParent()->tryQ(sols.angles(0,2));
00060 j.getParent()->getParent()->getParent()->tryQ(sols.angles(0,1));
00061 j.getParent()->getParent()->getParent()->getParent()->tryQ(sols.angles(0,0));
00062
00063 return sols.valid;
00064 }
00065
00066 IKCalliope::Solutions IKCalliope::closestThreeLinkIK(const fmat::Column<2>& t, const fmat::Column<3>& pEff, float prefPhi) const {
00067 fmat::Column<2> target = updatePosition(t, pEff, prefPhi);
00068 IKCalliope::Solutions solutions = threeLinkIK(target, prefPhi);
00069 if( solutions.valid )
00070 return solutions;
00071
00072
00073
00074 else {
00075 float pstep = M_PI/180;
00076 for(float deltaPhi = pstep; deltaPhi <= M_PI; deltaPhi += pstep) {
00077 target = updatePosition(t, pEff, AngSignPi(prefPhi + deltaPhi));
00078 solutions = threeLinkIK(target, AngSignPi(prefPhi + deltaPhi));
00079 if( solutions.valid )
00080 return solutions;
00081
00082 target = updatePosition(t, pEff, AngSignPi(prefPhi - deltaPhi));
00083 solutions = threeLinkIK(target, AngSignPi(prefPhi - deltaPhi));
00084 if( solutions.valid )
00085 return solutions;
00086 }
00087 }
00088 return punt(t);
00089 }
00090
00091 fmat::Column<2> IKCalliope::updatePosition(const fmat::Column<2>& t, const fmat::Column<3>& pEff, float oriThreeLink) const {
00092
00093 fmat::Column<2> gripperToWrist(kine->linkToLink(GripperFrameOffset, ArmWristOffset).translation());
00094 gripperToWrist = fmat::rotation2D(oriThreeLink) * gripperToWrist;
00095 fmat::Column<2> target = t - gripperToWrist;
00096
00097
00098 return target + fmat::rotation2D(oriThreeLink) * fmat::Column<2>(pEff);
00099 }
00100
00101 IKCalliope::Solutions IKCalliope::threeLinkIK(fmat::Column<2> t, float phi) const {
00102 IKCalliope::Solutions solutions;
00103 fmat::Matrix<2,2> sols_2link;
00104 fmat::Column<2> q3;
00105 float c2 = (t.sumSq() - L1*L1 - L2*L2) / (2*L1*L2);
00106 if(c2*c2 > 1) {
00107 solutions.noSols = 0;
00108 solutions.valid = false;
00109 return solutions;
00110 }
00111 else {
00112 sols_2link = twoLinkIK(t);
00113 q3[0] = phi - sols_2link(0,0) - sols_2link(0,1);
00114 q3[1] = phi - sols_2link(1,0) - sols_2link(1,1);
00115 solutions.angles(0,0) = sols_2link(0,0); solutions.angles(0,1) = sols_2link(0,1); solutions.angles(0,2) = q3[0];
00116 solutions.angles(1,0) = sols_2link(1,0); solutions.angles(1,1) = sols_2link(1,1); solutions.angles(1,2) = q3[1];
00117 solutions.noSols = 2;
00118 solutions = validAngles(solutions);
00119 return solutions;
00120 }
00121 }
00122
00123 IKCalliope::Solutions IKCalliope::punt(const fmat::Column<2>& target) const {
00124 IKCalliope::Solutions solutions;
00125 float q1 = fmat::atan(target), q2 = 0.0f, q3 = 0.0f;
00126 q1 = std::min(std::max(q1,jointLimits[0][0]),jointLimits[0][1]);
00127 solutions.angles(0,0) = q1; solutions.angles(0,1) = q2; solutions.angles(0,2) = q3;
00128 solutions.noSols = 1;
00129 solutions.valid = false;
00130 return solutions;
00131 }
00132
00133 fmat::Matrix<2,2> IKCalliope::twoLinkIK(fmat::Column<2> t) const {
00134 fmat::Matrix<2,2> ret;
00135 float c2 = (t.sumSq() - L1*L1 - L2*L2) / (2*L1*L2);
00136 float s2 = std::sqrt(1 - c2*c2);
00137 float q2 = std::atan2(s2, c2);
00138 float kQ = std::atan2(L2*s2,L1 + L2*c2);
00139 float q1plus = fmat::atan(t) - kQ;
00140 float q1minus = fmat::atan(t) + kQ;
00141 ret(0,0) = q1plus; ret(0,1) = q2;
00142 ret(1,0) = q1minus; ret(1,1) = -q2;
00143 return ret;
00144 }
00145
00146 IKCalliope::Solutions IKCalliope::validAngles(IKCalliope::Solutions solutions) const {
00147 int valid_solutions[2] = {0, 0};
00148 for (int sol_no = 0; sol_no < solutions.noSols; sol_no++) {
00149
00150 int val_angles = 0;
00151 for (int joint_no = 0; joint_no < 3; joint_no++) {
00152 if (solutions.angles(sol_no,joint_no) > jointLimits[joint_no][0] && solutions.angles(sol_no,joint_no) < jointLimits[joint_no][1])
00153 val_angles++;
00154 }
00155 if (val_angles == 3)
00156 valid_solutions[sol_no] = 1;
00157 }
00158 if (valid_solutions[0]+valid_solutions[1] == 2) {
00159 solutions.noSols = 2;
00160 solutions.valid = true;
00161 return solutions;
00162 }
00163 else if (valid_solutions[0]+valid_solutions[1] == 0) {
00164 solutions.noSols = 0;
00165 solutions.valid = false;
00166 return solutions;
00167 }
00168 else {
00169 if (valid_solutions[0] == 0)
00170 solutions.angles.row(0) = solutions.angles.row(1);
00171 solutions.noSols = 1;
00172 solutions.valid = true;
00173 return solutions;
00174 }
00175 }
00176
00177 IKSolver::StepResult_t IKCalliope::step(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float pDist, float posPri, const Orientation& oriTgt, float oriDist, float oriPri) const {
00178
00179 fmat::Transform Tj = j.getFullT();
00180 fmat::Column<3> pEffBase(Tj*pEff);
00181 fmat::Quaternion qj = j.getWorldQuaternion();
00182 Rotation oEffBase = qj*oriEff;
00183 Point de;
00184 pTgt.computeErrorGradient(pEffBase,oEffBase,de);
00185 StepResult_t res = SUCCESS;
00186 if(de.norm() > pDist) {
00187 de *= pDist/de.norm();
00188 res = PROGRESS;
00189 }
00190 Point pEffBaseP(pEffBase[1],pEffBase[2],pEffBase[3]);
00191 Point pTgtP = pEffBaseP+de;
00192 if(solve(pEff,oriEff,j,pTgtP,posPri,oriTgt,oriPri))
00193 return res;
00194 return LIMITS;
00195 }
00196
00197 # elif defined(TGT_IS_CALLIOPE2) // TGT_IS_CALLIOPE5
00198
00199 IKCalliope::IKCalliope() : baseToArm(), qOffset(), forearmLength() {
00200 const KinematicJoint* j = kine->getKinematicJoint(GripperFrameOffset);
00201
00202 forearmLength = (j->getWorldPosition() - j->getParent()->getParent()->getWorldPosition()).norm();
00203 qOffset = kine->getKinematicJoint(ArmBaseOffset)->qOffset;
00204 baseToArm = kine->getKinematicJoint(ArmBaseOffset)->getTo().inverse();
00205 }
00206
00207 bool IKCalliope::solve(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float posPri, const Orientation& oriTgt, float oriPri) const {
00208
00209 const Point& pTgtPoint = dynamic_cast<const Point&>(pTgt);
00210 Point pTgtBase(baseToArm * pTgtPoint);
00211
00212
00213
00214
00215
00216 float qBase = std::atan2(pTgtBase.y, pTgtBase.x);
00217 j.getParent()->getParent()->getParent()->tryQ(qBase-qOffset);
00218
00219
00220
00221 float opposite = pTgtBase[2];
00222 float qElbow;
00223 if (std::abs(opposite) < forearmLength)
00224 qElbow = std::asin(opposite / forearmLength);
00225 else
00226 qElbow = opposite > 0 ? M_PI_2 : -M_PI_2;
00227 j.getParent()->getParent()->tryQ(qElbow);
00228
00229 if ( (j.getWorldPosition() - pTgtBase).norm() < 5.0f )
00230 return true;
00231
00232 return false;
00233 }
00234
00235 IKSolver::StepResult_t IKCalliope::step(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float pDist, float posPri, const Orientation& oriTgt, float oriDist, float oriPri) const {
00236
00237 fmat::Transform Tj = j.getFullT();
00238 fmat::Column<3> pEffBase(Tj*pEff);
00239 fmat::Quaternion qj = j.getWorldQuaternion();
00240 Rotation oEffBase = qj*oriEff;
00241 Point de;
00242 pTgt.computeErrorGradient(pEffBase,oEffBase,de);
00243 StepResult_t res=SUCCESS;
00244 if(de.norm()>pDist) {
00245 de*=pDist/de.norm();
00246 res = PROGRESS;
00247 }
00248 Point pEffBaseP(pEffBase[1],pEffBase[2],pEffBase[3]);
00249 Point pTgtP = pEffBaseP+de;
00250 if(solve(pEff,oriEff,j,pTgtP,posPri,oriTgt,oriPri))
00251 return res;
00252 return LIMITS;
00253 }
00254
00255 # endif
00256
00257 #endif // TGT_HAS_ARMS