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));
00138 EXPECT_FALSE(BasicKin().linkTransforms(VectorXd(), poses, std::vector<std::string>()));
00139 EXPECT_FALSE(BasicKin().linkTransforms(VectorXd(), poses, link_names));
00140 EXPECT_FALSE(BasicKin().linkTransforms(VectorXd::Zero(6), poses, std::vector<std::string>()));
00141 EXPECT_FALSE(BasicKin().linkTransforms(VectorXd::Zero(6), poses, link_names));
00142
00143 EXPECT_FALSE(kin.linkTransforms(VectorXd(), poses, std::vector<std::string>()));
00144 EXPECT_FALSE(kin.linkTransforms(VectorXd::Zero(99), poses, link_names));
00145 EXPECT_FALSE(kin.linkTransforms(VectorXd::Constant(6, 1e10), poses, link_names));
00146
00147 EXPECT_TRUE(kin.linkTransforms(VectorXd::Zero(6), poses, link_names));
00148 EXPECT_TRUE(kin.linkTransforms(VectorXd::Zero(6), poses));
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));
00152
00153 link_names[5] = "fail_on_this";
00154 EXPECT_FALSE(kin.linkTransforms(VectorXd::Zero(6), poses, link_names));
00155 link_names_short[0] = link_names[5];
00156 EXPECT_FALSE(kin.linkTransforms(VectorXd::Zero(6), poses, link_names_short));
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
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));
00181 EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00182 EXPECT_TRUE(kin.linkTransforms(joint_angles, actual));
00183 EXPECT_GT(actual.size(), expected.size());
00184 actual.pop_back();
00185 EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00186
00187
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));
00198 EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00199 EXPECT_TRUE(kin.linkTransforms(joint_angles, actual));
00200 EXPECT_GT(actual.size(), expected.size());
00201 actual.pop_back();
00202 EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00203
00204
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));
00215 EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00216 EXPECT_TRUE(kin.linkTransforms(joint_angles, actual));
00217 EXPECT_GT(actual.size(), expected.size());
00218 actual.pop_back();
00219 EXPECT_TRUE(comparePoses(actual, expected, 1e-4));
00220
00221
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));
00232 EXPECT_TRUE(comparePoses(actual, expected_short, 1e-4));
00233 EXPECT_TRUE(kin.linkTransforms(joint_angles, actual));
00234 EXPECT_GT(actual.size(), expected.size());
00235 actual.pop_back();
00236 EXPECT_FALSE(comparePoses(actual, expected, 1e-4));
00237 }
00238
00240 TEST_F(RobotTest, calcFwdKinInputValidation)
00241 {
00242
00243 Eigen::Affine3d pose;
00244
00245 EXPECT_FALSE(BasicKin().calcFwdKin(VectorXd(), pose));
00246 EXPECT_FALSE(BasicKin().calcFwdKin(VectorXd::Zero(6), pose));
00247 EXPECT_FALSE(kin.calcFwdKin(VectorXd(), pose));
00248 EXPECT_FALSE(kin.calcFwdKin(VectorXd::Zero(99), pose));
00249 EXPECT_FALSE(kin.calcFwdKin(VectorXd::Constant(6, 1e10), pose));
00250
00251 EXPECT_TRUE(kin.calcFwdKin(VectorXd::Zero(6), pose));
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
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
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
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));
00294 EXPECT_FALSE(BasicKin().calcJacobian(VectorXd::Zero(6), jacobian));
00295 EXPECT_FALSE(kin.calcJacobian(VectorXd(), jacobian));
00296 EXPECT_FALSE(kin.calcJacobian(VectorXd::Zero(99), jacobian));
00297 EXPECT_FALSE(kin.calcJacobian(VectorXd::Constant(6, 1e10), jacobian));
00298
00299 EXPECT_TRUE(kin.calcJacobian(VectorXd::Zero(6), jacobian));
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
00313
00314 for(int j=0; j<10; j++)
00315 {
00316 for(int i=0; i<(int)joints.size(); i++)
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());
00336 double theta = r12.angle();
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;
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));
00354 EXPECT_FALSE(kin.solvePInv(MatrixXd(6,3), VectorXd(1), vResult));
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
00366 for (int i=0; i<100; ++i)
00367 ASSERT_TRUE(test_random(10, 10));
00368
00369
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