00001 #include "Shared/RobotInfo.h"
00002 #ifdef TGT_IS_HANDEYE
00003
00004 #include "Shared/debuget.h"
00005 #include "PlanarThreeLinkArm.h"
00006 #include "Shared/fmatSpatial.h"
00007 #include <math.h>
00008
00009 const std::string PlanarThreeLinkArm::autoRegisterPlanarThreeLinkArm = IKSolver::getRegistry().registerType<PlanarThreeLinkArm>("PlanarThreeLinkArm");
00010
00011 PlanarThreeLinkArm::PlanarThreeLinkArm() : L1(), L2(), L3(), jointLimits() {
00012
00013 unsigned int lastOff;
00014 #if defined(TGT_CHIARA) || defined(TGT_HANDEYE)
00015 lastOff = RobotInfo::GripperFrameOffset;
00016 #elif defined(TGT_HAS_ARMS)
00017 lastOff = ArmOffset+NumArmJoints-1;
00018 #else
00019 return;
00020 #endif
00021
00022 const KinematicJoint* j = kine->getKinematicJoint(lastOff);
00023 if ( j == NULL )
00024 throw std::runtime_error("PlanarThreeLinkArm can't find joint for end of arm");
00025
00026
00027 L1 = j->getParent()->getParent()->r;
00028 L2 = j->getParent()->r;
00029 L3 = j->r;
00030
00031 #if defined(TGT_HANDEYE)
00032 j = j->getParent();
00033 #endif
00034
00035 jointLimits[0][0] = j->getParent()->getParent()->qmin;
00036 jointLimits[0][1] = j->getParent()->getParent()->qmax;
00037 jointLimits[1][0] = j->getParent()->qmin;
00038 jointLimits[1][1] = j->getParent()->qmax;
00039 jointLimits[2][0] = j->qmin;
00040 jointLimits[2][1] = j->qmax;
00041
00042
00043 }
00044
00045 PlanarThreeLinkArm::PlanarThreeLinkArm(unsigned int offset) : L1(), L2(), L3(), jointLimits() {
00046 float linkLengths[3];
00047 for ( unsigned int j = offset; j < offset+3; j++) {
00048 linkLengths[j-offset] = kine->getKinematicJoint(j)->nextJoint()->r;
00049 jointLimits[j-offset][0] = kine->getKinematicJoint(j)->qmin;
00050 jointLimits[j-offset][1] = kine->getKinematicJoint(j)->qmax;
00051 }
00052
00053 L1 = linkLengths[0];
00054 L2 = linkLengths[1];
00055 L3 = linkLengths[2];
00056
00057
00058 }
00059
00060
00061 void PlanarThreeLinkArm::PrintVariables() const {
00062 std::cout << "L1: " << L1 << "\tL2: " << L2 << "\tL3 :" << L3 << std::endl;
00063 std::cout << "Shoulder joint limits:\t" << jointLimits[0][0] << "\t" << jointLimits[0][1] << std::endl;
00064 std::cout << "Elbow joint limits: \t" << jointLimits[1][0] << "\t" << jointLimits[1][1] << std::endl;
00065 std::cout << "Wrist joint limits: \t" << jointLimits[2][0] << "\t" << jointLimits[2][1] << std::endl;
00066 }
00067
00068 bool PlanarThreeLinkArm::solve(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float posPri, const Orientation& oriTgt, float oriPri) const {
00069
00070
00071 const Point& pTgtV = dynamic_cast<const Point&>(pTgt);
00072
00073
00074 const Rotation& oriTgtV = dynamic_cast<const Rotation&>(oriTgt);
00075 float ori = oriTgtV.axisComponent(fmat::UNIT3_Z);
00076
00077
00078 fmat::Column<2> target = fmat::rotation2D(ori) * fmat::pack(pEff.x, pEff.y) + fmat::pack(pTgtV.x, pTgtV.y);
00079
00080 PlanarThreeLinkArm::Solutions solutions = invKin3LinkRelaxPhi(target[0], target[1], ori);
00081
00082 j.getParent()->setQ(solutions.angles(0,2));
00083 j.getParent()->getParent()->setQ(solutions.angles(0,1));
00084 j.getParent()->getParent()->getParent()->setQ(solutions.angles(0,0));
00085 return true;
00086 }
00087
00088 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::invKin3LinkRelaxPhi(float x, float y, float pref_phi) const {
00089 PlanarThreeLinkArm::Solutions solutions;
00090 float delta_phi;
00091 if ( sqrt(x*x + y*y) > (L1+L2+L3) ) {
00092 return punt(x, y);
00093 }
00094
00095 solutions = invKin3Link(x,y,pref_phi);
00096 if( solutions.valid )
00097 return solutions;
00098
00099 else {
00100 for( int i = 1; i <= 18; i++) {
00101 delta_phi = i*10*(float)M_PI/180;
00102 solutions = invKin3Link(x,y,angNorm(pref_phi + delta_phi));
00103 if( solutions.valid ) {
00104 return solutions;
00105 }
00106 solutions = invKin3Link(x,y,angNorm(pref_phi - delta_phi));
00107 if( solutions.valid ) {
00108 return solutions;
00109 }
00110 }
00111 }
00112 solutions.noSols = 0; solutions.valid = false;
00113 return solutions;
00114 }
00115
00116 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::solveWithOffset(float x, float y, float pref_phi, fmat::Column<3> baseOffset) const {
00117 fmat::Column<3> basePoint = fmat::pack(x, y, 0);
00118
00119 fmat::Column<3> offset = fmat::rotationZ(pref_phi) * baseOffset;
00120 fmat::Column<3> point = basePoint + offset;
00121 return invKin3Link(point[0], point[1], pref_phi);
00122 }
00123
00124 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::invKin3Link(float x,float y,float phi) const {
00125 PlanarThreeLinkArm::Solutions solutions;
00126 fmat::Matrix<1,2> d3, p2;
00127 fmat::Matrix<2,2> sols_2link;
00128 fmat::Column<2> q3;
00129 d3(0,0) = L3 * std::cos(phi); d3(0,1) = L3 * std::sin(phi);
00130 p2(0,0) = x - d3(0,0); p2(0,1) = y - d3(0,1);
00131 float p2x = p2(0,0); float p2y = p2(0,1);
00132 float c2 = (p2x*p2x + p2y*p2y - L1*L1 - L2*L2) / (2*L1*L2);
00133 if(c2*c2 > 1) {
00134 solutions.noSols = 0;
00135 solutions.valid = false;
00136 return solutions;
00137 }
00138 else {
00139 sols_2link = invKin2Link(p2x,p2y,L1,L2);
00140 q3[0] = phi - sols_2link(0,0) - sols_2link(0,1);
00141 q3[1] = phi - sols_2link(1,0) - sols_2link(1,1);
00142 solutions.angles(0,0) = sols_2link(0,0); solutions.angles(0,1) = sols_2link(0,1); solutions.angles(0,2) = q3[0];
00143 solutions.angles(1,0) = sols_2link(1,0); solutions.angles(1,1) = sols_2link(1,1); solutions.angles(1,2) = q3[1];
00144 solutions.noSols = 2;
00145 solutions = validAngles(solutions);
00146 return solutions;
00147 }
00148 }
00149
00150 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::nearConfig(PlanarThreeLinkArm::Solutions sol, float elbow, bool valid) const{
00151 PlanarThreeLinkArm::Solutions ret_sol;
00152 if ( (sol.angles(0,1)/fabs(sol.angles(0,1))) == (elbow/fabs(elbow)) ) {
00153 ret_sol.angles(0,0) = sol.angles(0,0); ret_sol.angles(0,1) = sol.angles(0,1); ret_sol.angles(0,2) = sol.angles(0,2);
00154 ret_sol.noSols = 1; ret_sol.valid = valid;
00155 return ret_sol;
00156 }
00157 if (sol.noSols == 2) {
00158 if ( (sol.angles(1,1)/fabs(sol.angles(1,1))) == (elbow/fabs(elbow)) ) {
00159 ret_sol.angles(0,0) = sol.angles(1,0); ret_sol.angles(0,1) = sol.angles(1,1); ret_sol.angles(0,2) = sol.angles(1,2);
00160 ret_sol.noSols = 1; ret_sol.valid = valid;
00161 return ret_sol;
00162 }
00163 }
00164 ret_sol.noSols = 0; ret_sol.valid = false;
00165 return ret_sol;
00166 }
00167
00168 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::punt(float x, float y) const {
00169 PlanarThreeLinkArm::Solutions solutions;
00170 float q1 = std::atan2(y,x), q2 = 0.0f, q3 = 0.0f;
00171 q1 = std::min(std::max(q1,jointLimits[0][0]),jointLimits[0][1]);
00172 solutions.angles(0,0) = q1; solutions.angles(0,1) = q2; solutions.angles(0,2) = q3;
00173 solutions.noSols = 1;
00174 solutions.valid = false;
00175 return solutions;
00176 }
00177
00178 fmat::Matrix<2,2> PlanarThreeLinkArm::invKin2Link(float x,float y,float link1,float link2) const {
00179 fmat::Matrix<2,2> ret;
00180 float c2 = (x*x + y*y - link1*link1 - link2*link2) / (2*link1*link2);
00181 float s2minus = std::sqrt(1-c2*c2);
00182 float s2plus = -std::sqrt(1-c2*c2);
00183 float q2minus = std::atan2(s2minus,c2);
00184 float q2plus = std::atan2(s2plus,c2);
00185 float K1 = link1 + link2*c2;
00186 float K2plus = link2*s2plus;
00187 float K2minus = link2*s2minus;
00188 float q1minus = std::atan2(y,x) - std::atan2(K2minus,K1);
00189 float q1plus = std::atan2(y,x) - std::atan2(K2plus,K1);
00190 ret(0,0) = q1plus; ret(0,1) = q2plus;
00191 ret(1,0) = q1minus; ret(1,1) = q2minus;
00192 return ret;
00193 }
00194
00195 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::invKin2Link(float x,float y) const {
00196 PlanarThreeLinkArm::Solutions ret;
00197 float c2 = (x*x + y*y - L1*L1 - L2*L2) / (2*L1*L2);
00198
00199 if(c2*c2 > 1){
00200 bool noValid = true;
00201 while(noValid){
00202 if(std::fabs(x) > std::fabs(y)){
00203 if(x > 0)
00204 x = x - 1;
00205 else
00206 x = x + 1;
00207 }
00208 else if (std::fabs(y) > std::fabs(x)){
00209 if(y > 0)
00210 y = y - 1;
00211 else
00212 y = y + 1;
00213 }
00214 else{
00215 if(x > 0)
00216 x = x - 1;
00217 else
00218 x = x + 1;
00219 if(y > 0)
00220 y = y - 1;
00221 else
00222 y = y + 1;
00223 }
00224 c2 = (x*x + y*y - L1*L1 - L2*L2) / (2*L1*L2);
00225 if(c2*c2 <= 1)
00226 noValid = false;
00227 }
00228 }
00229
00230 float s2minus = std::sqrt(1-c2*c2);
00231 float s2plus = -std::sqrt(1-c2*c2);
00232 float q2minus = std::atan2(s2minus,c2);
00233 float q2plus = std::atan2(s2plus,c2);
00234 float K1 = L1 + L2*c2;
00235 float K2plus = L2*s2plus;
00236 float K2minus = L2*s2minus;
00237 float q1minus = std::atan2(y,x) - std::atan2(K2minus,K1);
00238 float q1plus = std::atan2(y,x) - std::atan2(K2plus,K1);
00239 ret.angles(0,0) = q1plus; ret.angles(0,1) = q2plus; ret.angles(0,2) = 0.0;
00240 ret.angles(1,0) = q1minus; ret.angles(1,1) = q2minus; ret.angles(1,2) = 0.0;
00241 return ret;
00242 }
00243 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::validAngles(PlanarThreeLinkArm::Solutions solutions) const {
00244 int valid_solutions[2] = {0, 0};
00245 fmat::Matrix<1,3> angles_set_1, angles_set_2;
00246 angles_set_1(0,0)=solutions.angles(0,0); angles_set_1(0,1)=solutions.angles(0,1); angles_set_1(0,2)=solutions.angles(0,2);
00247 angles_set_2(0,0)=solutions.angles(1,0); angles_set_2(0,1)=solutions.angles(1,1); angles_set_2(0,2)=solutions.angles(1,2);
00248 for( int sol_no = 0; sol_no < solutions.noSols; sol_no++ ) {
00249
00250 int val_angles = 0;
00251 for( int joint_no = 0; joint_no < 3; joint_no++ ) {
00252 if( !(solutions.angles(sol_no,joint_no) < jointLimits[joint_no][0] || solutions.angles(sol_no,joint_no) > jointLimits[joint_no][1]) )
00253 val_angles++;
00254 }
00255 if( val_angles == 3 )
00256 valid_solutions[sol_no] = 1;
00257 }
00258 if( valid_solutions[0]+valid_solutions[1] == 2 ) {
00259 solutions.noSols = 2;
00260 solutions.valid = true;
00261 return solutions;
00262 }
00263 else if( valid_solutions[0]+valid_solutions[1] == 0 ) {
00264 solutions.noSols = 0;
00265 solutions.valid = false;
00266 return solutions;
00267 }
00268 else {
00269 if( valid_solutions[0] == 0 ) {
00270 solutions.angles(0,0) = solutions.angles(1,0);
00271 solutions.angles(0,1) = solutions.angles(1,1);
00272 solutions.angles(0,2) = solutions.angles(1,2);
00273 }
00274 solutions.noSols = 1;
00275 solutions.valid = true;
00276 return solutions;
00277 }
00278 }
00279
00280 float PlanarThreeLinkArm::angDist(float a1,float a2) const {
00281
00282
00283 float angle = std::fmod(std::abs(a1 - a2),float(2*M_PI));
00284 if( angle > (float)M_PI )
00285 angle = float(2*M_PI) - angle;
00286 return angle;
00287 }
00288
00289 float PlanarThreeLinkArm::angNorm(float a) const {
00290
00291 float bias = (float)M_PI * (a/std::abs(a));
00292 float b = std::fmod(a+bias, float(2*M_PI)) - bias;
00293 return b;
00294 }
00295
00296 fmat::Matrix<2,2> PlanarThreeLinkArm::rot(float t) const {
00297
00298 fmat::Matrix<2,2> r;
00299 r(0,0)=std::cos(t); r(0,1)=-std::sin(t);
00300 r(1,0)=std::sin(t); r(1,1)=std::sin(t);
00301 return r;
00302 }
00303
00304 float PlanarThreeLinkArm::getL1() const{
00305 return (this->L1);
00306 }
00307
00308 float PlanarThreeLinkArm::getL2() const{
00309 return (this->L2);
00310 }
00311
00312 float PlanarThreeLinkArm::getL3() const{
00313 return (this->L3);
00314 }
00315
00316 void PlanarThreeLinkArm::setL1(float length1, float jointMax, float jointMin){
00317 this->L1 = length1;
00318 this->jointLimits[0][0] = jointMin;
00319 this->jointLimits[0][1] = jointMax;
00320 }
00321
00322 void PlanarThreeLinkArm::setL2(float length2, float jointMax, float jointMin){
00323 this->L2 = length2;
00324 this->jointLimits[1][0] = jointMin;
00325 this->jointLimits[1][1] = jointMax;
00326 }
00327
00328 void PlanarThreeLinkArm::setL3(float length3, float jointMax, float jointMin){
00329 this->L3 = length3;
00330 this->jointLimits[2][0] = jointMin;
00331 this->jointLimits[2][1] = jointMax;
00332 }
00333
00334 IKSolver::StepResult_t PlanarThreeLinkArm::step(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float pDist, float posPri, const Orientation& oriTgt, float oriDist, float oriPri) const {
00335
00336 fmat::Transform Tj = j.getFullT();
00337 fmat::Column<3> pEffBase(Tj*pEff);
00338 fmat::Quaternion qj = j.getWorldQuaternion();
00339 Rotation oEffBase = qj*oriEff;
00340 Point de;
00341 pTgt.computeErrorGradient(pEffBase,oEffBase,de);
00342 StepResult_t res=SUCCESS;
00343 if(de.norm()>pDist) {
00344 de*=pDist/de.norm();
00345 res = PROGRESS;
00346 }
00347 Point pEffBaseP(pEffBase[1],pEffBase[2],pEffBase[3]);
00348 Point pTgtP = pEffBaseP+de;
00349 if(solve(pEff,oriEff,j,pTgtP,posPri,oriTgt,oriPri))
00350 return res;
00351 return LIMITS;
00352 }
00353
00354 #endif //TGT_HANDEYE