DHParam.cpp
Go to the documentation of this file.
00001 
00018 #include <urdf2inventor/Helpers.h>
00019 #include <urdf2graspit/DHParam.h>
00020 #include <ros/ros.h>
00021 
00022 // epsilon for absolute values
00023 // measured in units of the world
00024 #define DH_ZERO_EPSILON 1e-05
00025 
00026 // epsilon for a dot product to be considered
00027 // a zero angle
00028 #define DH_ZERO_DOT_EPSILON 1e-03
00029     
00030 // similar to DH_ZERO_DOT_EPSILON, but
00031 // for the dot product considered as follows:
00032 //   double alpha = -v_1.dot(v);
00033 //   double det = std::fabs(1.0 - alpha * alpha);
00034 // #define DH_ZERO_DET_EPSILON 1e-02
00035 
00036 using urdf2graspit::DHParam;
00037 
00038 template<typename Derived> Eigen::VectorBlock<Derived, 2> subVec2(Eigen::MatrixBase<Derived>& v)
00039 {
00040     return Eigen::VectorBlock<Derived, 2>(v.derived(), 0);
00041 }
00042 
00043 bool equalAxis(const Eigen::Vector3d& z1, const Eigen::Vector3d& z2)
00044 {
00045     double dot = z1.dot(z2);
00046     return (std::fabs(dot - 1.0)) < DH_ZERO_DOT_EPSILON;
00047 }
00048 
00049 
00050 bool parallelAxis(const Eigen::Vector3d& z1, const Eigen::Vector3d& z2)
00051 {
00052     double dot = z1.dot(z2);
00053     //ROS_INFO_STREAM("Dot: "<<dot<<", diff: "<<std::fabs((std::fabs(dot) - 1.0)));
00054     return std::fabs((std::fabs(dot) - 1.0)) < DH_ZERO_DOT_EPSILON;
00055 }
00056 
00062 int equalOrParallelAxis(const Eigen::Vector3d& z1, const Eigen::Vector3d& z2)
00063 {
00064     double dot = z1.dot(z2);
00065     // ROS_INFO_STREAM("Equal or parallel: "<<z1<<" (len "<<z1.norm()<<"), "<<z2<<" (len "<<z2.norm()<<")");
00066     // ROS_INFO_STREAM("Dot: "<<dot<<", diff: "<<std::fabs((std::fabs(dot) - 1.0))<<", angle="<<acos(dot)*180/M_PI);
00067     bool parallel = std::fabs((std::fabs(dot) - 1.0)) < DH_ZERO_DOT_EPSILON;
00068     bool equal = std::fabs(dot - 1.0) < DH_ZERO_DOT_EPSILON;
00069     if (equal) return 2;
00070     if (parallel) return 1;
00071     return 0;
00072 }
00073 
00074 
00075 bool intersectLinePlane(const Eigen::Vector3d& linePoint, const Eigen::Vector3d& lineDir,
00076         const Eigen::Vector3d& planePoint, const Eigen::Vector3d& n,
00077         Eigen::Vector3d& intersect)
00078 {
00079     if (fabs(lineDir.dot(n)) < DH_ZERO_DOT_EPSILON)
00080     {
00081         ROS_ERROR_STREAM("Line "<<lineDir<<" and plane "<<n<<" are parallel");
00082         return false;
00083     }    
00084 
00085     // The equation of a plane (points P are on the plane):
00086     //      n dot (p - planePoint) = 0
00087     // Which can be expanded to:
00088     //      n dot p - n dot planePoint = 0
00089     // and then
00090     //      n dot p = n dot planePoint
00091     // The equation of the line (points p on the line along lineDir):
00092     //      p = linePoint + u * lineDir 
00093     // The intersection of these two occurs when
00094     //      n dot (linePoint + u * lineDir) = n dot planePoint
00095     // expanded:
00096     //      n dot linePoint + n dot (u*lineDir) = n dot planePoint
00097     //      n dot (u*lineDir)   = (n dot planePoint) - (n dot linePoint)
00098     //      n dot (u*lineDir)   = n dot (planePoint - linePoint)
00099     //      u * (n dot lineDir) = n dot (planePoint - linePoint)
00100     //      u  = (n dot (planePoint - linePoint)) / (n dot lineDir)
00101 
00102     double u = n.dot(planePoint-linePoint) / n.dot(lineDir);
00103     intersect = linePoint + lineDir*u;
00104     return true;
00105 }
00106 
00107 
00114 double squaredLinesDistance(const Eigen::Vector3d& zi_1, const Eigen::Vector3d& zi,
00115                             const Eigen::Vector3d& pi_1, const Eigen::Vector3d& pi,
00116                             bool& parallel, Eigen::Vector3d& cli_1, Eigen::Vector3d& cli)
00117 {
00118     parallel = false;
00119 
00120     Eigen::Vector3d diff = pi_1 - pi;
00121     double alpha = -zi_1.dot(zi);
00122     double bi_1 = diff.dot(zi_1);
00123     double c = diff.squaredNorm();
00124     double det = std::fabs(1.0 - alpha * alpha);
00125     double det2 = std::fabs(1.0 - std::fabs(alpha));
00126     double bi, si_1, si, sqrDist;
00127 
00128     // ROS_INFO_STREAM("Zi-1 "<<zi_1<<", zi "<<zi<<" alpha: "<<alpha<<" cos: "<<acos(alpha)<<", det "<<det);
00129 
00130     //if (det >= DH_ZERO_DET_EPSILON)
00131     if (det2 >= DH_ZERO_DOT_EPSILON)
00132     {
00133         // Lines are not parallel.
00134         bi = -diff.dot(zi);
00135         double invDet = 1.0 / det;
00136         si_1 = (alpha * bi - bi_1) * invDet;
00137         si = (alpha * bi_1 - bi) * invDet;
00138         sqrDist = si_1 * (si_1 + alpha * si + 2.0 * bi_1) +
00139                   si * (alpha * si_1 + si + 2.0 * bi) + c;
00140     }
00141     else
00142     {
00143         // Lines are parallel, select any closest pair of points.
00144         si_1 = -bi_1;
00145         si = 0.0;
00146         sqrDist = bi_1 * si_1 + c;
00147         parallel = true;
00148     }
00149 
00150     cli_1 = pi_1 + si_1 * zi_1;
00151     cli = pi + si * zi;
00152 
00153     // Account for numerical round-off errors.
00154     if (sqrDist < 0.0)
00155     {
00156         sqrDist = 0.0;
00157     }
00158 
00159     return sqrDist;
00160 }
00161 
00162 
00163 
00164 #if 1
00165 
00166 // returns sqrt(squaredLinesDistance(...))
00167 double linesDistance(const Eigen::Vector3d& zi_1, const Eigen::Vector3d& zi,
00168                      const Eigen::Vector3d& pi_1, const Eigen::Vector3d& pi,
00169                      bool& parallel, Eigen::Vector3d& cli_1, Eigen::Vector3d& cli)
00170 {
00171     return sqrt(squaredLinesDistance(zi_1, zi, pi_1, pi, parallel, cli_1, cli));
00172 }
00173 
00174 #else
00175 
00176 // another, not yet fully tested, implementation of linesDistance().
00177 double linesDistance(const Eigen::Vector3d& zi_1, const Eigen::Vector3d& zi,
00178                      const Eigen::Vector3d& pi_1, const Eigen::Vector3d& pi,
00179                      bool& parallel, Eigen::Vector3d& cli_1, Eigen::Vector3d& cli)
00180 {
00181     parallel=parallelAxis(zi_1,zi);
00182     if (parallel)
00183     {
00184         ROS_WARN("Not tested yet: parallel z axes");
00185         cli_1=pi_1;
00186         cli=pi;
00187         Eigen::Vector3d pi_conn=pi_1-pi;
00188         if (pi_conn.norm() < DH_ZERO_EPSILON)
00189         {
00190             ROS_INFO("DHParam debug info: pi_1 and pi are equal");
00191             return 0;
00192         }
00193         if (std::fabs(pi_conn.dot(zi_1)) < DH_ZERO_DOT_EPSILON)
00194         {
00195             ROS_INFO("DHParam debug info: points are already on closest line");
00196             return pi_conn.norm();
00197         }
00198         Eigen::Vector3d lineDir = zi_1;
00199         Eigen::Vector3d linePoint = pi_1;
00200         Eigen::Vector3d point = pi;
00201         Eigen::Vector3d linePointPlaneN = lineDir.cross(linePoint-point);
00202         Eigen::Vector3d distLine = linePointPlaneN.cross(lineDir);
00203         if (!intersectLinePlane(point, distLine, linePoint, distLine, cli_1))
00204         {
00205             ROS_ERROR("Could not intersect line and plane");
00206             return 0;
00207         }
00208         cli = point;
00209     }
00210 
00211     ROS_INFO("Lines are skew");
00212 
00213     Eigen::Vector3d n=zi_1.cross(zi);
00214     if (std::fabs(n.norm()-1.0) > DH_ZERO_EPSILON)
00215     {
00216         ROS_ERROR_STREAM("DHParams: n should be of uniform length! Is "
00217             <<n.norm()<<" and obtained from "<<zi_1<<" (len "
00218             <<zi_1.norm()<<"), "<<zi<<"("<<zi.norm()<<"), dot "<<zi_1.dot(zi));
00219         return 0;
00220     }
00221 
00222     // plane containing zi_1, parallel to n 
00223     Eigen::Vector3d zi_1_n = n.cross(zi_1);
00224     // plane containing zi, parallel to n 
00225     Eigen::Vector3d zi_n = n.cross(zi);
00226     
00227     if (!intersectLinePlane(pi, zi, pi_1, zi_1_n, cli))
00228     {
00229         ROS_ERROR("Could not intersect line along zi with plane through zi_1");
00230         return 0;
00231     }
00232     
00233     if (!intersectLinePlane(pi_1, zi_1, pi, zi_n, cli_1))
00234     {
00235         ROS_ERROR("Could not intersect line along zi with plane through zi_1");
00236         return 0;
00237     }
00238 
00239     return (cli_1-cli).norm();
00240 }
00241 #endif
00242 
00243 
00244 #if 0
00245 bool DHParam::getRAndAlpha(const Eigen::Vector3d& zi_1, const Eigen::Vector3d& zi,
00246                            const Eigen::Vector3d& pi_1, const Eigen::Vector3d& pi,
00247                            double& r, double& alpha,
00248                            Eigen::Vector3d& commonNormal, Eigen::Vector3d& nOriginOnZi_1)
00249 {
00250     ROS_INFO_STREAM("getRAndAlpha for "<<zi_1<<", "<<zi);
00251 
00252     bool parallel = false;
00253     if (!getCommonNormal(zi_1, zi, pi_1, pi, commonNormal, nOriginOnZi_1, r, parallel))
00254     {
00255         ROS_ERROR("Common normal can't be obtained");
00256         alpha = 0;
00257         return false;
00258     }
00259 
00260     ROS_INFO_STREAM("Common normal: "<<commonNormal);
00261 
00262     if (std::fabs(zi_1.dot(commonNormal)) > DH_ZERO_DOT_EPSILON)
00263     {
00264         ROS_ERROR_STREAM("Consistency: Zi-1 and common normal not orthogonal: "<<zi_1.dot(commonNormal)<<", zi_1 = "<<zi_1<<", commonNormal = "<<commonNormal);
00265         ROS_INFO_STREAM("angle "<<acos(zi_1.dot(commonNormal))*180/M_PI);
00266         return false;
00267     }
00268     if (std::fabs(zi.dot(commonNormal)) > DH_ZERO_DOT_EPSILON)
00269     {
00270         ROS_ERROR_STREAM("Consistency: Zi and common normal not orthogonal: "<<zi.dot(commonNormal)<<", zi = "<<zi<<", commonNormal = "<<commonNormal);
00271         ROS_INFO_STREAM("angle "<<acos(zi.dot(commonNormal))*180/M_PI);
00272         return false;
00273     }
00274 
00275     // ROS_INFO_STREAM("Common normal of "<<zi_1<<" and "<<zi<<": "<<commonNormal<<"(parallel: "<<parallel<<", len="<<commonNormal.norm()<<")");
00276     
00277     int zAxEqPl = equalOrParallelAxis(zi_1, zi);
00278     if ((zAxEqPl > 0) != parallel)
00279     {
00280         ROS_ERROR_STREAM("Consistency in DHParams functions: "
00281             <<"both functions must have considered axes parallel. zi: " 
00282             <<zi_1<<" zi: "<<zi<<", parallel = "
00283             <<parallel<<" zAxEqPl = "<<zAxEqPl);
00284     }
00285 
00286     if (parallel)
00287     {
00288         ROS_INFO("DEBUG-INFO DHParam: Parallel case for getRAndAlpha");
00289         // Re-set nOriginOnZi_1:
00290         // TODO: Should we consider this case:
00291         // a) if joint is revolute, set to pi_1 (so that parameter d in the end will be calculated to 0)
00292         // b) if joint is prismatic, locate it at a reference position?
00293         nOriginOnZi_1 = pi_1;
00294         alpha = 0;
00295         if (zAxEqPl != 2)
00296         {   // correct alpha to be 
00297             ROS_INFO_STREAM("DEBUG-INFO DHParam: Correcting alpha for "<<zi<<" as it's not equal to  "<<zi_1);
00298             alpha = M_PI;
00299         }
00300         return true;
00301     }
00302 
00303     // for alpha, rotation is to be counter-clockwise around x
00304     alpha = acos(zi_1.dot(zi));
00305     Eigen::AngleAxisd corr(alpha, commonNormal);
00306     Eigen::Vector3d corrV = corr * zi_1;
00307     int corrEqPl = equalOrParallelAxis(zi, corrV);
00308     if (corrEqPl != 2)
00309     { 
00310         // correct alpha so that it causes a counter-clockwise
00311         // rotation around x
00312         ROS_INFO_STREAM("DEBUG-INFO DHParams: Correcting alpha (is "
00313                         <<alpha<<"): "<<zi<<", "<<corrV);
00314         alpha = -alpha;
00315     }
00316     
00317     if (fabs(r) < 1e-07) r=0;
00318     if (fabs(alpha) < 1e-07) alpha=0;
00319     return true;
00320 }
00321 #endif
00322 
00323 bool DHParam::getAlpha(const Eigen::Vector3d& zi_1, const Eigen::Vector3d& zi,
00324                            const Eigen::Vector3d& pi_1, const Eigen::Vector3d& pi,
00325                            const Eigen::Vector3d& xi, double& alpha)
00326 {
00327     // ROS_INFO_STREAM("getAlpha for "<<zi_1<<", "<<zi);
00328 
00329     int zAxEqPl = equalOrParallelAxis(zi_1, zi);
00330     if (zAxEqPl > 0)
00331     {
00332         ROS_INFO("DEBUG-INFO DHParam: Parallel case for getAlpha");
00333         alpha = 0;
00334         if (zAxEqPl != 2)
00335         {   // correct alpha to be 
00336             ROS_INFO_STREAM("DEBUG-INFO DHParam: Correcting alpha for "<<zi<<" as it's not equal to  "<<zi_1);
00337             alpha = M_PI;
00338         }
00339         return true;
00340     }
00341 
00342     // for alpha, rotation is to be counter-clockwise around x
00343     alpha = acos(zi_1.dot(zi));
00344     Eigen::AngleAxisd corr(alpha, xi);
00345     Eigen::Vector3d corrV = corr * zi_1;
00346     int corrEqPl = equalOrParallelAxis(zi, corrV);
00347     if (corrEqPl != 2)
00348     { 
00349         // correct alpha so that it causes a counter-clockwise
00350         // rotation around x
00351         ROS_INFO_STREAM("DEBUG-INFO DHParams: Correcting alpha (is "
00352                         <<alpha<<"): "<<zi<<", "<<corrV);
00353         alpha = -alpha;
00354     }
00355     
00356     if (fabs(alpha) < 1e-07) alpha=0;
00357     return true;
00358 }
00359 
00360 
00361 bool DHParam::getDAndTheta(const Eigen::Vector3d& zi_1,
00362                            const Eigen::Vector3d& xi_1,
00363                            const Eigen::Vector3d& pi_1,
00364                            const Eigen::Vector3d& xi,
00365                            const Eigen::Vector3d& normOriginOnZi_1,
00366                            double& d, double& theta)
00367 {
00368     Eigen::Vector3d originDiff = normOriginOnZi_1 - pi_1;
00369     d = originDiff.norm();
00370     // ROS_INFO_STREAM("getDAndTheta, difference along z "<<originDiff<<" (d = "<<d<<")");
00371     if (d > DH_ZERO_EPSILON)
00372     {
00373       originDiff.normalize();  // normalize for call of equalOrParallelAxis
00374       int zAxEqPl = equalOrParallelAxis(originDiff, zi_1);
00375       if (zAxEqPl == 0)
00376       {
00377         // neither equal nor parallel
00378         ROS_ERROR_STREAM("Consistency: translation along z axis should have "
00379                          <<"been parallel or equal to the z axis!"
00380                          <<originDiff<<", "<<zi_1<<" (normOriginOnZ="<<normOriginOnZi_1<<")");
00381         return false;
00382       }
00383       else if (zAxEqPl == 1)
00384       {
00385         ROS_INFO_STREAM("DEBUG-INFO: Translation along z parallel to z, but not equal, so d is negative");
00386         d = -d;
00387       }
00388     }
00389 
00390     if ((xi_1.norm() < DH_ZERO_EPSILON) || (xi.norm() < DH_ZERO_EPSILON))
00391     {
00392         ROS_WARN("One of the x-axises is 0, hence theta will be 0");
00393         theta = 0;
00394         return true;
00395     }
00396 
00397     // theta is angle between common normal (xi) and xi_1 around zi_1
00398     theta = acos(xi_1.dot(xi));
00399     // ROS_INFO_STREAM("Theta: Angle between "<<xi<<" and "<<xi_1<<" is "<<theta);
00400     if (std::fabs(theta) < DH_ZERO_EPSILON)
00401     {
00402         return true;
00403     }
00404 
00405     // maybe adapt sign, as rotation is counter-clockwise around x
00406     Eigen::AngleAxisd corr(theta, zi_1);
00407     Eigen::Vector3d corrV = corr * xi_1;
00408     int corrEqPl = equalOrParallelAxis(xi, corrV);
00409     if (corrEqPl != 2)
00410     {   // correct alpha to be 
00411         theta = -theta;
00412         ROS_INFO_STREAM("DEBUG-INFO DHParams: Correcting theta: "<<xi<<", "<<corrV
00413                         <<", theta="<<theta);
00414     }
00415 
00416     if (fabs(theta) < 1e-07) theta=0;
00417     if (fabs(d) < 1e-07) d=0;
00418       
00419     return true;
00420 }
00421 
00422 bool DHParam::toDenavitHartenberg(DHParam& param,
00423                                   const Eigen::Vector3d& zi_1,
00424                                   const Eigen::Vector3d& xi_1,
00425                                   const Eigen::Vector3d& pi_1,
00426                                   const Eigen::Vector3d& zi,
00427                                   const Eigen::Vector3d& pi,
00428                                   Eigen::Vector3d& xi)
00429 {
00430     // get the common normal, which is going to be the new x axis
00431     bool parallel = false;
00432     Eigen::Vector3d nOriginOnZi_1;
00433     if (!getCommonNormal(zi_1, zi, pi_1, pi, xi, nOriginOnZi_1, param.r, parallel))
00434     {
00435         ROS_ERROR("Common normal can't be obtained");
00436         return false;
00437     }
00438 
00439     if (std::fabs(zi_1.dot(xi)) > DH_ZERO_DOT_EPSILON)
00440     {
00441         ROS_ERROR_STREAM("Consistency: Zi-1 and common normal not orthogonal: "<<zi_1.dot(xi)<<", zi_1 = "<<zi_1<<", xi = "<<xi);
00442         ROS_INFO_STREAM("angle "<<acos(zi_1.dot(xi))*180/M_PI);
00443         return false;
00444     }
00445     if (std::fabs(zi.dot(xi)) > DH_ZERO_DOT_EPSILON)
00446     {
00447         ROS_ERROR_STREAM("Consistency: Zi and common normal not orthogonal: "<<zi.dot(xi)<<", zi = "<<zi<<", xi = "<<xi);
00448         ROS_INFO_STREAM("angle "<<acos(zi.dot(xi))*180/M_PI);
00449         return false;
00450     }
00451 
00452     // ROS_INFO_STREAM("Common normal of "<<zi_1<<" and "<<zi<<": "<<xi<<"(parallel: "<<parallel<<", closest point="<<nOriginOnZi_1<<")");
00453    
00454     // just a consistency check to see that equalOrParallelAxis works the same
00455     // as the return value of parallel from getCommonNormal(): 
00456     int zAxEqPl = equalOrParallelAxis(zi_1, zi);
00457     if ((zAxEqPl > 0) != parallel)
00458     {
00459         ROS_ERROR_STREAM("Consistency in DHParams functions: "
00460             <<"both functions must have considered axes parallel. zi: " 
00461             <<zi_1<<" zi: "<<zi<<", parallel = "
00462             <<parallel<<" zAxEqPl = "<<zAxEqPl);
00463     }
00464 
00465     // the common normal is parallel  
00466     if (parallel)
00467     {
00468         ROS_INFO("DEBUG-INFO DHParam: Parallel case for getCommonNormal");
00469         // nOriginOnZi_1 should already by pi_1 (set by getCommonNormal).
00470         // But get this case anyway for debugging.
00471         // TODO: Should we consider this case:
00472         // a) if joint is revolute, set to pi_1 (so that parameter d in the end will be calculated to 0)
00473         // b) if joint is prismatic, locate it at a reference position?
00474         nOriginOnZi_1 = pi_1;
00475     }
00476     
00477     // cap small values close to 0
00478     if (fabs(param.r) < 1e-07) param.r=0;
00479 
00480     if (!getAlpha(zi_1, zi, pi_1, pi, xi, param.alpha))
00481     //if (!getRAndAlpha(zi_1, zi, pi_1, pi, param.r, param.alpha, xi, nOriginOnZi_1))
00482     {
00483         ROS_ERROR("Could not get alpha");
00484         return false;
00485     }
00486 
00487     // ROS_INFO_STREAM("Got alpha " << param.alpha << ". ");
00488     if (!getDAndTheta(zi_1, xi_1, pi_1, xi, nOriginOnZi_1, param.d, param.theta))
00489     {
00490         ROS_ERROR("Could not get d and theta");
00491         return false;
00492     }
00493 
00494 /*
00495     // Do the full transform of the joint pose pi_1
00496     // to pi, this may have changed pi.
00497     EigenTransform transform = EigenTransform::Identity();
00498     Eigen::Vector3d z(0,0,1);
00499     transform.rotate(Eigen::AngleAxisd(param.theta,z));
00500     transform.translate(z*param.d);
00501     ROS_INFO_STREAM("..Translated along z by "<<param.d<<": "<<transform * pi_1);
00502     Eigen::Vector3d x(1,0,0); 
00503     transform.rotate(Eigen::AngleAxisd(param.alpha,x));
00504     transform.translate(x*param.r);
00505 
00506     Eigen::Vector3d pi_new = transform * pi_1;
00507     ROS_INFO_STREAM("PI_NEW: "<<pi_new<<" ( vs URDF space "<<pi<<" )");
00508     pi = pi_new;
00509 
00510 */
00511 
00512 
00513     return true;
00514 }
00515 
00516 
00517 
00518 bool DHParam::getCommonNormal(const Eigen::Vector3d& zi_1, const Eigen::Vector3d& zi,
00519                               const Eigen::Vector3d& pi_1, const Eigen::Vector3d& pi,
00520                               Eigen::Vector3d& commonNormal, Eigen::Vector3d& nOriginOnZi_1,
00521                               double& shortestDistance, bool& parallel)
00522 {
00523     parallel = false;
00524     Eigen::Vector3d cli_1;
00525     Eigen::Vector3d cli;
00526 
00527     shortestDistance = linesDistance(zi_1, zi, pi_1, pi, parallel, cli_1, cli);
00528 
00529     nOriginOnZi_1 = cli_1;
00530 
00531     if (shortestDistance < DH_ZERO_EPSILON)
00532     { 
00533         // lines intersect or are equal
00534         if ((zi_1 - zi).norm() < DH_ZERO_EPSILON)
00535         {  
00536             // if the z axis were found equal, also the lines at their poses must
00537             // be equal. Do some consistency checks to assert that. 
00538             if (!parallel)
00539             {
00540                 ROS_ERROR("DHParam: inconsistency, lines should have been found parallel");
00541             }
00542             Eigen::Vector3d testP = pi - pi_1;
00543             if (testP.norm() > 1e-05)  // if poses are the same, that's fine
00544             {
00545               // poses are different, then their difference must be collinear
00546               // with the z axes
00547               testP.normalize();
00548               if ((fabs(testP.dot(zi)) - 1) > 1e-03)
00549               {
00550                 ROS_ERROR("DHParam: inconsistency, lines should be collinear");
00551               }
00552             }
00553 
00554             // z axises are equal. Take any perpendicular axis to z.
00555             ROS_WARN_STREAM("z-axes equal. Common normal cannot be obtained ("
00556                << zi_1 << " at " << pi_1 << ", " << zi << " at " << pi << ")"
00557                << ", taking any perpendicular axis.");
00558             
00559             // take cross product with any axis (will be perpendicular)
00560             Eigen::Vector3d cross = Eigen::Vector3d::UnitX().cross(zi);
00561             if (cross.norm() < 1e-03) 
00562             {
00563               cross = Eigen::Vector3d::UnitY().cross(zi);
00564               if (cross.norm() < 1e-03) 
00565               {
00566                 cross = Eigen::Vector3d::UnitZ().cross(zi);
00567                 if (cross.norm() < 1e-03) 
00568                 {
00569                   ROS_ERROR_STREAM("Could not determine perpendicular normal");
00570                   commonNormal = Eigen::Vector3d(0, 0, 0);
00571                   return false;
00572                 }
00573               }
00574             }
00575             commonNormal = cross;
00576         }
00577         else
00578         {   // z-axes intersect
00579             ROS_INFO_STREAM("DEBUG-INFO: z-axes intersect! "<<zi_1<<" at "<<pi_1<<", "<<zi<<" at "<<pi);
00580             commonNormal = zi_1.cross(zi);
00581             // commonNormal.normalize();
00582         }
00583         // ROS_INFO_STREAM("Lines are parallel. Shortest distance: "<<shortestDistance<<". Common normal: "<<commonNormal);
00584     }
00585     else
00586     {
00587         commonNormal = cli - cli_1;
00588         // ROS_INFO_STREAM("Lenght of diff: " << commonNormal.norm());
00589         commonNormal.normalize();
00590         /*if (!parallel) ROS_INFO_STREAM("Lines are skew. Shortest distance: "
00591                                        <<shortestDistance<<". Common normal: "<<commonNormal);
00592         else ROS_INFO_STREAM("Lines are parallel. Closest points: "
00593                              <<cli<<", "<<cli_1<<". Shortest distance: "
00594                              <<shortestDistance<<". Common normal: "<<commonNormal);*/
00595     }
00596 
00597     // consistency check
00598     // ROS_INFO_STREAM("Normal length: "<<commonNormal.norm());
00599     if (std::fabs(commonNormal.norm()-1.0) > DH_ZERO_EPSILON)
00600     {
00601         ROS_ERROR_STREAM("DHParams: common normal should be of uniform length! Is "
00602             <<commonNormal.norm()<<" and obtained from "<<zi_1<<" (len "
00603             <<zi_1.norm()<<"), "<<zi<<" (len "<<zi.norm()<<"), dot "<<zi_1.dot(zi));
00604         return false;
00605     }
00606 
00607     // normalize, just to smooth out inaccuracies
00608     commonNormal.normalize();
00609 
00610     if (parallel)
00611     {
00612         nOriginOnZi_1 = pi_1;
00613     }
00614     return true;
00615 }
00616 
00617 DHParam::EigenTransform DHParam::getTransform(const DHParam& p)
00618 {
00619     Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
00620 
00621     EigenTransform ret;
00622     ret.setIdentity();
00623 
00624 #if 1
00625 
00626     double ct = cos(p.theta);
00627     double ca = cos(p.alpha);
00628     double st = sin(p.theta);
00629     double sa = sin(p.alpha);
00630     m(0, 0) = ct;
00631     m(0, 1) = -st * ca;
00632     m(0, 2) = st * sa;
00633     m(0, 3) = p.r * ct;
00634     m(1, 0) = st;
00635     m(1, 1) = ct * ca;
00636     m(1, 2) = -ct * sa;
00637     m(1, 3) = p.r * st;
00638     m(2, 0) = 0;
00639     m(2, 1) = sa;
00640     m(2, 2) = ca;
00641     m(2, 3) = p.d;
00642 
00643     ret = EigenTransform(m);
00644 
00645 #else
00646 
00647     //this is how graspit computes the transformation matrix,
00648     //which actually amounts to the same, as rotating around one axis and
00649     //then translating along the same is commutative.
00650     ret.setIdentity();
00651     Eigen::AngleAxisd trot(p.theta,Eigen::Vector3d(0,0,1));
00652     ret.rotate(trot);
00653     ret.translate(Eigen::Vector3d(0,0,p.d));
00654     Eigen::AngleAxisd arot(p.alpha,Eigen::Vector3d(1,0,0));
00655     ret.translate(Eigen::Vector3d(p.r,0,0));
00656     ret.rotate(arot);
00657 
00658     ROS_INFO_STREAM("Transform compares: "<<std::endl<<ret<<std::endl<<EigenTransform(m));
00659 #endif
00660     return ret;
00661 }
00662 
00663 
00664 
00665 DHParam::EigenTransform DHParam::getTransform(const urdf::Pose& p)
00666 {
00667     urdf::Vector3 _jtr = p.position;
00668     Eigen::Vector3d jtr(_jtr.x, _jtr.y, _jtr.z);
00669     urdf::Rotation _jrot = p.rotation;
00670     Eigen::Quaterniond jrot(_jrot.w, _jrot.x, _jrot.y, _jrot.z);
00671     jrot.normalize();
00672     DHParam::EigenTransform tr;
00673     tr.setIdentity();
00674     tr = tr.translate(jtr);
00675     tr = tr.rotate(jrot);
00676     return tr;
00677 }
00678 
00679 // Get joint transform to parent
00680 DHParam::EigenTransform DHParam::getTransform(const DHParam::JointConstPtr& joint)
00681 {
00682     return getTransform(joint->parent_to_joint_origin_transform);
00683 }
00684 
00685 
00686 bool DHParam::getTransforms(const std::vector<DHParam>& dh, const bool dh2urdf,
00687                             std::map<std::string,EigenTransform>& transforms)
00688 {
00689     // starting from the root of a chain, these are the current
00690     // reference frame transforms in the chain,
00691     // one in DH space, and one in URDF space
00692     EigenTransform refFrameDH;
00693     EigenTransform refFrameURDF;
00694     refFrameDH.setIdentity();
00695     refFrameURDF.setIdentity();
00696 
00697     JointConstPtr root_joint;
00698     int chainCnt = -1;
00699     bool resetChain = false;
00700     for (std::vector<DHParam>::const_iterator it = dh.begin(); it != dh.end(); ++it)
00701     {
00702         if (resetChain)
00703         {
00704             refFrameDH.setIdentity();
00705             refFrameURDF.setIdentity();
00706             chainCnt = -1;
00707         }
00708         resetChain = false;
00709 
00710         ++chainCnt;
00711         JointConstPtr joint = it->joint;
00712         LinkConstPtr childLink = it->childLink;
00713         if (!childLink.get())
00714         {
00715             ROS_ERROR("DHParam::urdf2DHTransforms: child link is NULL");
00716             return false;
00717         }
00718 
00719         if (childLink->child_joints.empty())
00720         {
00721             // this is the end link, and we've defined the end frame to be
00722             // at the same location as the last joint,
00723             // so no rotation should be needed?
00724             resetChain = true;  // reset chain in next iteration
00725         }
00726 
00727         EigenTransform dhTrans = DHParam::getTransform(*it);
00728 
00729         EigenTransform jointTransform = EigenTransform::Identity();
00730         if (chainCnt > 0) jointTransform = getTransform(joint);
00731 
00732         // ROS_INFO_STREAM("Dh trans for "<<joint->name<<": "<<dhTrans);
00733         // ROS_INFO_STREAM("Joint trans for "<<joint->name<<": "<<jointTransform);
00734 
00735         refFrameDH = refFrameDH * dhTrans;
00736         refFrameURDF = refFrameURDF * jointTransform;
00737 
00738         EigenTransform trans;
00739         if (dh2urdf)
00740         {   // dhSpaceToJointSpace
00741             trans = refFrameDH.inverse() * refFrameURDF;
00742         }
00743         else
00744         {   // jointSpaceToDH 
00745             trans = refFrameURDF.inverse() * refFrameDH;
00746         }
00747 
00748         // ROS_INFO_STREAM("Doing transform for joint "<<joint->name<<": "<<dhSpaceToJointSpace);
00749         if (!transforms.insert(std::make_pair(childLink->name, trans)).second)
00750         {
00751             ROS_ERROR_STREAM("Consistency: The link "<<childLink->name<<" was already encountered");
00752             return false;
00753         }
00754     }
00755     return true;
00756 }
00757 


urdf2graspit
Author(s): Jennifer Buehler
autogenerated on Wed May 8 2019 02:53:45