test_basic_kin.cpp
Go to the documentation of this file.
00001 
00028 #include <gtest/gtest.h>
00029 #include <ros/ros.h>
00030 #include <constrained_ik/basic_kin.h>
00031 #include <boost/assign/list_of.hpp>
00032 #include <eigen_conversions/eigen_kdl.h>
00033 #include <moveit/robot_model_loader/robot_model_loader.h>
00034 #include <moveit/robot_model/joint_model_group.h>
00035 #include <boost/random/uniform_int_distribution.hpp>
00036 
00037 using constrained_ik::basic_kin::BasicKin;
00038 using Eigen::MatrixXd;
00039 using Eigen::VectorXd;
00040 
00041 const std::string GROUP_NAME = "manipulator"; 
00042 const std::string ROBOT_DESCRIPTION_PARAM = "robot_description"; 
00048 class BaseTest : public :: testing::Test
00049 {
00050 protected:
00051   BasicKin kin; 
00052 };
00053 
00055 class RobotTest : public BaseTest
00056 {
00057 protected:
00058 
00059   robot_model_loader::RobotModelLoaderPtr loader_; 
00060   moveit::core::RobotModelPtr robot_model_; 
00063   virtual void SetUp()
00064   {
00065 
00066     loader_.reset(new robot_model_loader::RobotModelLoader(ROBOT_DESCRIPTION_PARAM));
00067     robot_model_ = loader_->getModel();
00068 
00069     ASSERT_TRUE(robot_model_ != nullptr);
00070     ASSERT_TRUE(kin.init(robot_model_->getJointModelGroup(GROUP_NAME)));
00071   }
00072 
00080   bool comparePoses(const std::vector<KDL::Frame> &actual, const std::vector<KDL::Frame> &expected, const double tol = 1e-6)
00081   {
00082       bool rtn;
00083 
00084       if (actual.size() != expected.size())
00085       {
00086         ROS_ERROR("comparePoses, number of poses different");
00087         return false;
00088       }
00089       for (size_t ii=0; ii<actual.size(); ++ii)
00090       {
00091         if (!KDL::Equal(actual[ii], expected[ii], tol))
00092         {
00093           ROS_ERROR("failure at pose %d",(int) ii);
00094           return false;
00095         }
00096       }
00097       return true;
00098   }
00099 };
00100 
00102 class PInvTest : public RobotTest
00103 {
00104 protected:
00111   bool test_random(int rows, int cols)
00112   {
00113     MatrixXd A = MatrixXd::Random(rows, cols);
00114     VectorXd x = VectorXd::Random(cols);
00115     VectorXd b = A*x;
00116     VectorXd rslt;
00117 
00118     bool status = kin.solvePInv(A, b, rslt);
00119     return status && rslt.isApprox(x, 1e-10);
00120   }
00121 };
00122 
00124 TEST_F(RobotTest, inputValidation)
00125 {
00126   EXPECT_FALSE(kin.init(NULL));
00127   EXPECT_TRUE(kin.init(robot_model_->getJointModelGroup(GROUP_NAME)));
00128 }
00129 
00131 TEST_F(RobotTest, linkTransformsInputValidation)
00132 {
00133     std::vector<std::string> link_names = boost::assign::list_of("shoulder_link")("upper_arm_link")("forearm_link")("wrist_1_link")("wrist_2_link")("wrist_3_link");
00134     std::vector<KDL::Frame> poses;
00135     int n_links = link_names.size();
00136 
00137     EXPECT_FALSE(BasicKin().linkTransforms(VectorXd(), poses));                                     // un-init BasicKin, names, & Jnts
00138     EXPECT_FALSE(BasicKin().linkTransforms(VectorXd(), poses, std::vector<std::string>()));         // un-init BasicKin, names, & Jnts
00139     EXPECT_FALSE(BasicKin().linkTransforms(VectorXd(), poses, link_names));                         // un-init BasicKin & Jnts
00140     EXPECT_FALSE(BasicKin().linkTransforms(VectorXd::Zero(6), poses, std::vector<std::string>()));  // un-init BasicKin & names
00141     EXPECT_FALSE(BasicKin().linkTransforms(VectorXd::Zero(6), poses, link_names));                  // un-init BasicKin
00142 
00143     EXPECT_FALSE(kin.linkTransforms(VectorXd(), poses, std::vector<std::string>()));                // empty names & joints
00144     EXPECT_FALSE(kin.linkTransforms(VectorXd::Zero(99), poses, link_names));                        // too many joints
00145     EXPECT_FALSE(kin.linkTransforms(VectorXd::Constant(6, 1e10), poses, link_names));               // joints out-of-range
00146 
00147     EXPECT_TRUE(kin.linkTransforms(VectorXd::Zero(6), poses, link_names));                          // valid input
00148     EXPECT_TRUE(kin.linkTransforms(VectorXd::Zero(6), poses));                                      // valid input
00149 
00150     std::vector<std::string> link_names_short = boost::assign::list_of(link_names[5]);
00151     EXPECT_TRUE(kin.linkTransforms(VectorXd::Zero(6), poses, link_names_short));                    //valid short input
00152 
00153     link_names[5] = "fail_on_this";
00154     EXPECT_FALSE(kin.linkTransforms(VectorXd::Zero(6), poses, link_names));                         // invalid link list
00155     link_names_short[0] = link_names[5];
00156     EXPECT_FALSE(kin.linkTransforms(VectorXd::Zero(6), poses, link_names_short));                   // invalid & short link list
00157 }
00158 
00160 TEST_F(RobotTest, linkTransformsKnownPoses)
00161 {
00162     using KDL::Rotation;
00163     using KDL::Vector;
00164     using KDL::Frame;
00165 
00166     std::vector<std::string> link_names = boost::assign::list_of("shoulder_link")("upper_arm_link")("forearm_link")("wrist_1_link")("wrist_2_link")("wrist_3_link");
00167     VectorXd joint_angles(6);
00168     std::vector<Frame> actual, expected(6);
00169 
00170     //0,0,0,0,0,0
00171     joint_angles = VectorXd::Zero(6);
00172     expected[0] = Frame(KDL::Rotation::Quaternion(0.0, 0.0 , 0.0 , 1.0), Vector(0.000000, 0.000000, 0.127300));              
00173     expected[1] = Frame(KDL::Rotation::Quaternion(0.0, 0.707107, 0.0, 0.707107), Vector(0.000000, 0.220941, 0.127300));
00174     expected[2] = Frame(KDL::Rotation::Quaternion(0.0, 0.707107, 0.0, 0.707107), Vector(0.612000, 0.049041, 0.127300));
00175     expected[3] = Frame(KDL::Rotation::Quaternion(0.0, 1.0, 0.0, 0.0), Vector(1.184300, 0.049041, 0.127300));
00176     expected[4] = Frame(KDL::Rotation::Quaternion(0.0, 1.0, 0.0, 0.0), Vector(1.184300, 0.163941, 0.127300));
00177     expected[5] = Frame(KDL::Rotation::Quaternion(0.0, 1.0, 0.0, 0.0), Vector(1.184300, 0.163941, 0.011600));
00178     kin.linkTransforms(joint_angles, actual, link_names);
00179     
00180     EXPECT_TRUE(kin.linkTransforms(joint_angles, actual, link_names));  //all link names
00181     EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00182     EXPECT_TRUE(kin.linkTransforms(joint_angles, actual));              //no link names (defaults to all)
00183     EXPECT_GT(actual.size(), expected.size());
00184     actual.pop_back(); //for comparison remove ee_link which is not in list of test links.
00185     EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00186 
00187     //90,0,0,0,0,0
00188     joint_angles(0) = M_PI_2;
00189     expected[0] = Frame(KDL::Rotation::Quaternion(0.0, 0.0 , 0.707107, 0.707107), Vector(0.000000, 0.000000, 0.127300));              
00190     expected[1] = Frame(KDL::Rotation::Quaternion(-0.5, 0.5, 0.5, 0.5), Vector(-0.220941, 0.000000, 0.127300));
00191     expected[2] = Frame(KDL::Rotation::Quaternion(-0.5, 0.5, 0.5, 0.5), Vector(-0.049041, 0.612000, 0.127300));
00192     expected[3] = Frame(KDL::Rotation::Quaternion(-0.707107, 0.707107, 0.0, 0.0), Vector(-0.049041, 1.184300, 0.127300));
00193     expected[4] = Frame(KDL::Rotation::Quaternion(-0.707107, 0.707107, 0.0, 0.0), Vector(-0.163941, 1.184300, 0.127300));
00194     expected[5] = Frame(KDL::Rotation::Quaternion(-0.707107, 0.707107, 0.0, 0.0), Vector(-0.163941, 1.184300, 0.011600));
00195     kin.linkTransforms(joint_angles, actual, link_names);
00196 
00197     EXPECT_TRUE(kin.linkTransforms(joint_angles, actual, link_names));  //all link names
00198     EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00199     EXPECT_TRUE(kin.linkTransforms(joint_angles, actual));              //no link names (defaults to all)
00200     EXPECT_GT(actual.size(), expected.size());
00201     actual.pop_back(); //for comparison remove ee_link which is not in list of test links.
00202     EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00203 
00204     //0,-90,0,0,0,0
00205     joint_angles(0) = 0.;
00206     joint_angles(1) = -M_PI_2;
00207     expected[0] = Frame(KDL::Rotation::Quaternion(0.000000, 0.000000, 0.000000, 1.000000), Vector(0.000000, 0.000000, 0.127300));              
00208     expected[1] = Frame(KDL::Rotation::Quaternion(0.000000, -0.000000, 0.000000, 1.000000), Vector(0.000000, 0.220941, 0.127300));              
00209     expected[2] = Frame(KDL::Rotation::Quaternion(0.000000, -0.000000, 0.000000, 1.000000), Vector(-0.000000, 0.049041, 0.739300));              
00210     expected[3] = Frame(KDL::Rotation::Quaternion(0.000000, 0.707107, 0.000000, 0.707107), Vector(-0.000000, 0.049041, 1.311600));              
00211     expected[4] = Frame(KDL::Rotation::Quaternion(0.000000, 0.707107, 0.000000, 0.707107), Vector(-0.000000, 0.163941, 1.311600));              
00212     expected[5] = Frame(KDL::Rotation::Quaternion(0.000000, 0.707107, 0.000000, 0.707107), Vector(0.115700, 0.163941, 1.311600));              
00213     kin.linkTransforms(joint_angles, actual, link_names);
00214     EXPECT_TRUE(kin.linkTransforms(joint_angles, actual, link_names));  //all link names
00215     EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00216     EXPECT_TRUE(kin.linkTransforms(joint_angles, actual));              //no link names (defaults to all)
00217     EXPECT_GT(actual.size(), expected.size());
00218     actual.pop_back(); //for comparison remove ee_link which is not in list of test links.
00219     EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00220 
00221     //joints 2-5
00222     joint_angles = VectorXd::Zero(6);
00223     std::vector<std::string> link_names_short(link_names.begin()+1, link_names.end()-1);
00224     expected[1] = Frame(KDL::Rotation::Quaternion(0.000000, 0.707107, 0.000000, 0.707107), Vector(0.000000, 0.220941, 0.127300));
00225     expected[2] = Frame(KDL::Rotation::Quaternion(0.000000, 0.707107, 0.000000, 0.707107), Vector(0.612000, 0.049041, 0.127300));
00226     expected[3] = Frame(KDL::Rotation::Quaternion(0.000000, 1.000000, 0.000000, 0.000000), Vector(1.184300, 0.049041, 0.127300));
00227     expected[4] = Frame(KDL::Rotation::Quaternion(0.000000, 1.000000, 0.000000, 0.000000), Vector(1.184300, 0.163941, 0.127300));
00228     std::vector<Frame> expected_short(expected.begin()+1, expected.end()-1);
00229     kin.linkTransforms(joint_angles, actual, link_names);
00230 
00231     EXPECT_TRUE(kin.linkTransforms(joint_angles, actual, link_names_short));    //all link names
00232     EXPECT_TRUE(comparePoses(actual, expected_short, 1e-4));
00233     EXPECT_TRUE(kin.linkTransforms(joint_angles, actual));                      //no link names (defaults to all)
00234     EXPECT_GT(actual.size(), expected.size());
00235     actual.pop_back(); //for comparison remove ee_link which is not in list of test links.
00236     EXPECT_FALSE(comparePoses(actual, expected, 1e-4));
00237 }
00238 
00240 TEST_F(RobotTest, calcFwdKinInputValidation)
00241 {
00242   //test for calcFwdKin(joints, pose)
00243   Eigen::Affine3d pose;
00244 
00245   EXPECT_FALSE(BasicKin().calcFwdKin(VectorXd(), pose));            // un-init BasicKin & Jnts
00246   EXPECT_FALSE(BasicKin().calcFwdKin(VectorXd::Zero(6), pose));     // un-init BasicKin
00247   EXPECT_FALSE(kin.calcFwdKin(VectorXd(), pose));                   // empty joints
00248   EXPECT_FALSE(kin.calcFwdKin(VectorXd::Zero(99), pose));           // too many joints
00249   EXPECT_FALSE(kin.calcFwdKin(VectorXd::Constant(6, 1e10), pose));  // joints out-of-range
00250 
00251   EXPECT_TRUE(kin.calcFwdKin(VectorXd::Zero(6), pose));             // valid input
00252 }
00253 
00255 TEST_F(RobotTest, calcFwdKinKnownPoses)
00256 {
00257   VectorXd joints = VectorXd::Zero(6);
00258   Eigen::Affine3d expected, result;
00259   double base_to_tip;
00260   double base_to_tip_expected;
00261   // all joints 0
00262   EXPECT_TRUE(kin.calcFwdKin(joints, result));
00263   double x = result.translation().x();
00264   double y = result.translation().y();
00265   double z = result.translation().z();
00266   base_to_tip_expected  = x*x + y*y + z*z;
00267 
00268   // 1st joint 90 deg,all others 0
00269   joints(0) = M_PI_2;
00270   EXPECT_TRUE(kin.calcFwdKin(joints, result));
00271   x = result.translation().x();
00272   y = result.translation().y();
00273   z = result.translation().z();
00274   base_to_tip = x*x + y*y + z*z;
00275   EXPECT_NEAR(base_to_tip, base_to_tip_expected, 1e-3);
00276 
00277   // last joint -90, all others 0
00278   joints(0) = 0.0;
00279   joints(5) = -M_PI_2;
00280   EXPECT_TRUE(kin.calcFwdKin(joints, result));
00281   x = result.translation().x();
00282   y = result.translation().y();
00283   z = result.translation().z();
00284   base_to_tip = x*x + y*y + z*z;
00285   EXPECT_NEAR(base_to_tip, base_to_tip_expected, 1e-3);
00286 
00287 }
00288 
00290 TEST_F(RobotTest, calcJacobianInputValidation)
00291 {
00292     Eigen::MatrixXd jacobian;
00293     EXPECT_FALSE(BasicKin().calcJacobian(VectorXd(), jacobian));            // un-init BasicKin & Jnts
00294     EXPECT_FALSE(BasicKin().calcJacobian(VectorXd::Zero(6), jacobian));     // un-init BasicKin
00295     EXPECT_FALSE(kin.calcJacobian(VectorXd(), jacobian));                   // empty joints
00296     EXPECT_FALSE(kin.calcJacobian(VectorXd::Zero(99), jacobian));           // too many joints
00297     EXPECT_FALSE(kin.calcJacobian(VectorXd::Constant(6, 1e10), jacobian));  // joints out-of-range
00298 
00299     EXPECT_TRUE(kin.calcJacobian(VectorXd::Zero(6), jacobian));             // valid input
00300 }
00301 
00303 TEST_F(RobotTest, calcJacobianKnownPoses)
00304 {
00305   VectorXd joints = VectorXd(6);
00306   VectorXd updated_joints = VectorXd(6);
00307   MatrixXd jacobian;
00308   Eigen::Affine3d pose;
00309   boost::random::mt19937 rng;  
00310   double delta = 1e-3;
00311   
00312   // use random joint states, compute the numerical Jacobian and compare to that computed
00313   // all joints at a random pose
00314   for(int j=0; j<10; j++)// try 10 different poses
00315   {
00316     for(int i=0; i<(int)joints.size(); i++)  // find a random pose
00317     {
00318       boost::random::uniform_int_distribution<int> angle_degrees(-180, 180) ;
00319       joints[i] = angle_degrees(rng)* 3.14/180.0;
00320     }
00321     kin.calcFwdKin(joints,pose);
00322     EXPECT_TRUE(kin.calcJacobian(joints, jacobian));
00323     for(int i=0; i<(int) joints.size(); i++)
00324     {
00325       updated_joints = joints;
00326       updated_joints[i] += delta;
00327       Eigen::Affine3d updated_pose;
00328       kin.calcFwdKin(updated_joints, updated_pose);
00329       double delta_x = (updated_pose.translation().x() - pose.translation().x())/delta;
00330       double delta_y = (updated_pose.translation().y() - pose.translation().y())/delta;
00331       double delta_z = (updated_pose.translation().z() - pose.translation().z())/delta;
00332       EXPECT_NEAR(delta_x, jacobian(0,i), 1e-3);
00333       EXPECT_NEAR(delta_y, jacobian(1,i), 1e-3);
00334       EXPECT_NEAR(delta_z, jacobian(2,i), 1e-3);
00335       Eigen::AngleAxisd r12(pose.rotation().transpose()*updated_pose.rotation());   // rotation from p1 -> p2
00336       double theta = r12.angle();          // TODO: move rangedAngle to utils class
00337       theta = copysign(fmod(fabs(theta),2.0*M_PI), theta);
00338       if (theta < -M_PI) theta = theta+2.*M_PI;
00339       if (theta > M_PI)  theta = theta-2.*M_PI;
00340       Eigen::VectorXd omega = (pose.rotation() * r12.axis() * theta)/delta;                        // axis k * theta expressed in frame0
00341       EXPECT_NEAR(omega(0), jacobian(3,i), 1e-3);
00342       EXPECT_NEAR(omega(1), jacobian(4,i), 1e-3);
00343       EXPECT_NEAR(omega(2), jacobian(5,i), 1e-3);
00344     }
00345   }
00346 }
00347 
00349 TEST_F(PInvTest, solvePInvInputValidation)
00350 {
00351   VectorXd vResult;
00352 
00353   EXPECT_FALSE(kin.solvePInv(MatrixXd(), VectorXd(), vResult)); // will generate ROS_ERROR("Empty matrices not supported in solvePinv()");
00354   EXPECT_FALSE(kin.solvePInv(MatrixXd(6,3), VectorXd(1), vResult)); // will generate ROS_ERROR("Matrix size mismatch:...");
00355   EXPECT_TRUE(kin.solvePInv(MatrixXd::Zero(6,3), VectorXd::Zero(6), vResult));
00356   EXPECT_TRUE(kin.solvePInv(MatrixXd::Zero(3,6), VectorXd::Zero(3), vResult));
00357   EXPECT_TRUE(kin.solvePInv(MatrixXd::Zero(6,6), VectorXd::Zero(6), vResult));
00358 }
00359 
00361 TEST_F(PInvTest, solvePInvRandomInputs)
00362 {
00363   VectorXd vResult;
00364 
00365   // Test square matrices
00366   for (int i=0; i<100; ++i)
00367     ASSERT_TRUE(test_random(10, 10));
00368 
00369   // Test over-constrained matrices
00370   for (int i=0; i<100; ++i)
00371     ASSERT_TRUE(test_random(10, 5));
00372 }
00373 
00375 int main(int argc, char **argv)
00376 {
00377   testing::InitGoogleTest(&argc, argv);
00378   ros::init(argc,argv,"test_BasicKin");
00379   ros::NodeHandle nh;
00380   return RUN_ALL_TESTS();
00381 }
00382 


constrained_ik
Author(s): Chris Lewis , Jeremy Zoss , Dan Solomon
autogenerated on Sat Jun 8 2019 19:23:45