test_ekf_localization_node_interfaces.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 #include <nav_msgs/Odometry.h>
00003 #include <geometry_msgs/PoseWithCovarianceStamped.h>
00004 #include <geometry_msgs/TwistWithCovarianceStamped.h>
00005 
00006 #include <gtest/gtest.h>
00007 #include <iostream>
00008 
00009 #include <tf/tf.h>
00010 
00011 nav_msgs::Odometry filtered_;
00012 
00013 void resetFilter()
00014 {
00015   ros::NodeHandle nh;
00016   ros::Publisher setPosePub = nh.advertise<geometry_msgs::PoseWithCovarianceStamped>("/set_pose", 5);
00017 
00018   bool poseChanged = false;
00019 
00020   geometry_msgs::PoseWithCovarianceStamped pose;
00021   pose.pose.pose.orientation.w = 1;
00022   pose.header.frame_id = "odom";
00023   for(size_t ind = 0; ind < 36; ind+=7)
00024   {
00025     pose.pose.covariance[ind] = 1e-6;
00026   }
00027 
00028   // Make sure the pose reset worked. Test will timeout
00029   // if this fails.
00030   while(!poseChanged)
00031   {
00032     pose.header.stamp = ros::Time::now();
00033     setPosePub.publish(pose);
00034     pose.header.seq++;
00035     ros::spinOnce();
00036 
00037     poseChanged = (filtered_.pose.pose.position.x == pose.pose.pose.position.x) &&
00038                   (filtered_.pose.pose.position.y == pose.pose.pose.position.y) &&
00039                   (filtered_.pose.pose.position.z == pose.pose.pose.position.z) &&
00040                   (filtered_.pose.pose.orientation.x == pose.pose.pose.orientation.x) &&
00041                   (filtered_.pose.pose.orientation.y == pose.pose.pose.orientation.y) &&
00042                   (filtered_.pose.pose.orientation.z == pose.pose.pose.orientation.z) &&
00043                   (filtered_.pose.pose.orientation.w == pose.pose.pose.orientation.w);
00044 
00045     ros::Duration(0.1).sleep();
00046   }
00047 
00048 }
00049 
00050 void filterCallback(const nav_msgs::OdometryConstPtr &msg)
00051 {
00052   filtered_ = *msg;
00053 }
00054 
00055 TEST (InterfacesTest, OdomPoseBasicIO)
00056 {
00057   ros::NodeHandle nh;
00058   ros::Publisher odomPub = nh.advertise<nav_msgs::Odometry>("/odom_input0", 5);
00059 
00060   ros::Subscriber filteredSub = nh.subscribe("/odometry/filtered", 1, &filterCallback);
00061 
00062   nav_msgs::Odometry odom;
00063   odom.pose.pose.position.x = 20.0;
00064   odom.pose.pose.position.y = 10.0;
00065   odom.pose.pose.position.z = -40.0;
00066   
00067   odom.pose.covariance[0] = 2.0;
00068   odom.pose.covariance[7] = 2.0;
00069   odom.pose.covariance[14] = 2.0;
00070 
00071   odom.header.frame_id = "odom";
00072   odom.child_frame_id = "base_link";
00073 
00074   for(size_t i = 0; i < 10; ++i)
00075   {
00076     odom.header.stamp = ros::Time::now();
00077     odomPub.publish(odom);
00078     ros::spinOnce();
00079 
00080     ros::Duration(0.1).sleep();
00081 
00082     odom.header.seq++;
00083 
00084     /*double roll, pitch, yaw;
00085     tf::Quaternion quat;
00086     tf::quaternionMsgToTF(filtered_.pose.pose.orientation, quat);
00087     tf::Matrix3x3 mat(quat);
00088     mat.getRPY(roll, pitch, yaw);
00089     std::cerr << filtered_.pose.pose.position.x << " " << filtered_.pose.pose.position.y << " " << filtered_.pose.pose.position.z << "\n  " << roll << " " << pitch << " " << yaw << "\n";*/
00090   }
00091 
00092 
00093   // Now check the values from the callback
00094   EXPECT_EQ(filtered_.pose.pose.position.x, odom.pose.pose.position.x);
00095   EXPECT_EQ(filtered_.pose.pose.position.y, 0); // Configuration for this variable for this sensor is false
00096   EXPECT_EQ(filtered_.pose.pose.position.z, odom.pose.pose.position.z);
00097 
00098   EXPECT_LT(filtered_.pose.covariance[0], 0.5);
00099   EXPECT_LT(filtered_.pose.covariance[7], 0.25); // Configuration for this variable for this sensor is false
00100   EXPECT_LT(filtered_.pose.covariance[14], 0.5);
00101 
00102   resetFilter();
00103 }
00104 
00105 TEST (InterfacesTest, OdomTwistBasicIO)
00106 {
00107   ros::NodeHandle nh;
00108   ros::Publisher odomPub = nh.advertise<nav_msgs::Odometry>("/odom_input2", 5);
00109   ros::Publisher setPosePub = nh.advertise<geometry_msgs::PoseWithCovarianceStamped>("/set_pose", 5);
00110   ros::Subscriber filteredSub = nh.subscribe("/odometry/filtered", 1, &filterCallback);
00111 
00112   nav_msgs::Odometry odom;
00113   odom.twist.twist.linear.x = 0;
00114   odom.twist.twist.linear.y = 0;
00115   odom.twist.twist.linear.z = 0;
00116   odom.twist.twist.angular.x = 0;
00117   odom.twist.twist.angular.y = 0;
00118   odom.twist.twist.angular.z = M_PI / 2.0;
00119 
00120   odom.twist.covariance[0] = 1e-6;
00121   odom.twist.covariance[7] = 1e-6;
00122   odom.twist.covariance[14] = 1e-6;
00123   odom.twist.covariance[21] = 1e-6;
00124   odom.twist.covariance[28] = 1e-6;
00125   odom.twist.covariance[35] = 1e-6;
00126 
00127   odom.header.frame_id = "odom";
00128   odom.child_frame_id = "base_link";
00129 
00130   for(size_t i = 0; i < 10; ++i)
00131   {
00132     odom.header.stamp = ros::Time::now();
00133     odomPub.publish(odom);
00134     ros::spinOnce();
00135 
00136     ros::Duration(0.1).sleep();
00137 
00138     odom.header.seq++;
00139 
00140     /*double roll, pitch, yaw;
00141     tf::Quaternion quat;
00142     tf::quaternionMsgToTF(filtered_.pose.pose.orientation, quat);
00143     tf::Matrix3x3 mat(quat);
00144     mat.getRPY(roll, pitch, yaw);
00145     std::cerr << filtered_.pose.pose.position.x << " " << filtered_.pose.pose.position.y << " " << filtered_.pose.pose.position.z << "\n  " << roll << " " << pitch << " " << yaw << "\n";*/
00146   }
00147 
00148   odom.twist.twist.linear.x = 0.5;
00149   odom.twist.twist.linear.y = 0;
00150   odom.twist.twist.linear.z = 0;
00151   odom.twist.twist.angular.x = 0;
00152   odom.twist.twist.angular.y = 0;
00153   odom.twist.twist.angular.z = 0;
00154 
00155   for(size_t i = 0; i < 10; ++i)
00156   {
00157     odom.header.stamp = ros::Time::now();
00158     odomPub.publish(odom);
00159     ros::spinOnce();
00160 
00161     ros::Duration(0.1).sleep();
00162 
00163     odom.header.seq++;
00164   }
00165 
00166   //std::cerr << filtered_;
00167   EXPECT_LT(::fabs(filtered_.pose.pose.position.x), 0.2);
00168   EXPECT_LT(::fabs(filtered_.pose.pose.position.y - 0.5), 0.2);
00169 
00170   resetFilter();
00171 }
00172 
00173 TEST (InterfacesTest, PoseBasicIO)
00174 {
00175   ros::NodeHandle nh;
00176   ros::Publisher posePub = nh.advertise<geometry_msgs::PoseWithCovarianceStamped>("/pose_input0", 5);
00177   ros::Subscriber filteredSub = nh.subscribe("/odometry/filtered", 1, &filterCallback);
00178 
00179   geometry_msgs::PoseWithCovarianceStamped pose;
00180   pose.pose.pose.position.x = 20.0;
00181   pose.pose.pose.position.y = 10.0;
00182   pose.pose.pose.position.z = -40.0;
00183   pose.pose.pose.orientation.x = 0;
00184   pose.pose.pose.orientation.y = 0;
00185   pose.pose.pose.orientation.z = 0;
00186   pose.pose.pose.orientation.w = 1;
00187 
00188   for(size_t ind = 0; ind < 36; ind+=7)
00189   {
00190     pose.pose.covariance[ind] = 1e-6;
00191   }
00192 
00193   pose.header.frame_id = "odom";
00194 
00195   bool poseChanged = false;
00196 
00197   // Make sure the pose reset worked. Test will timeout
00198   // if this fails.
00199   while(!poseChanged)
00200   {
00201     pose.header.stamp = ros::Time::now();
00202     posePub.publish(pose);
00203     pose.header.seq++;
00204     ros::spinOnce();
00205 
00206     poseChanged = ::fabs(filtered_.pose.pose.position.x - pose.pose.pose.position.x) < 1e-5 &&
00207                   ::fabs(filtered_.pose.pose.position.z - pose.pose.pose.position.z) < 1e-5;
00208 
00209     ros::Duration(0.1).sleep();
00210   }
00211 
00212   // Now check the values from the callback
00213   EXPECT_LT(filtered_.pose.pose.position.y, 1e-7); // Configuration for this variable for this sensor is false
00214   EXPECT_LT(filtered_.pose.covariance[0], 0.1);
00215   EXPECT_LT(filtered_.pose.covariance[7], 2.0);
00216   EXPECT_LT(filtered_.pose.covariance[14], 0.1);
00217 
00218   poseChanged = false;
00219 
00220   resetFilter();
00221 }
00222 
00223 TEST (InterfacesTest, TwistBasicIO)
00224 {
00225   ros::NodeHandle nh;
00226   ros::Publisher twistPub = nh.advertise<geometry_msgs::TwistWithCovarianceStamped>("/twist_input0", 5);
00227   ros::Subscriber filteredSub = nh.subscribe("/odometry/filtered", 1, &filterCallback);
00228 
00229   geometry_msgs::TwistWithCovarianceStamped twist;
00230   twist.twist.twist.linear.x = 0;
00231   twist.twist.twist.linear.y = 0;
00232   twist.twist.twist.linear.z = 0;
00233   twist.twist.twist.angular.x = M_PI / 2.0;
00234   twist.twist.twist.angular.y = 0;
00235   twist.twist.twist.angular.z = 0;
00236 
00237   twist.twist.covariance[0] = 1e-6;
00238   twist.twist.covariance[7] = 1e-6;
00239   twist.twist.covariance[14] = 1e-6;
00240   twist.twist.covariance[21] = 1e-6;
00241   twist.twist.covariance[28] = 1e-6;
00242   twist.twist.covariance[35] = 1e-6;
00243 
00244   twist.header.frame_id = "base_link";
00245 
00246   for(size_t i = 0; i < 10; ++i)
00247   {
00248     twist.header.stamp = ros::Time::now();
00249     twistPub.publish(twist);
00250     ros::spinOnce();
00251 
00252     ros::Duration(0.1).sleep();
00253 
00254     twist.header.seq++;
00255 
00256     /*double roll, pitch, yaw;
00257     tf::Quaternion quat;
00258     tf::quaternionMsgToTF(filtered_.pose.pose.orientation, quat);
00259     tf::Matrix3x3 mat(quat);
00260     mat.getRPY(roll, pitch, yaw);
00261     std::cerr << filtered_.pose.pose.position.x << " " << filtered_.pose.pose.position.y << " " << filtered_.pose.pose.position.z << "\n  " << roll << " " << pitch << " " << yaw << "\n";*/
00262   }
00263 
00264   twist.twist.twist.linear.x = 0;
00265   twist.twist.twist.linear.y = -0.5;
00266   twist.twist.twist.linear.z = 0;
00267   twist.twist.twist.angular.x = 0;
00268   twist.twist.twist.angular.y = 0;
00269   twist.twist.twist.angular.z = 0;
00270 
00271   for(size_t i = 0; i < 10; ++i)
00272   {
00273     twist.header.stamp = ros::Time::now();
00274     twistPub.publish(twist);
00275     ros::spinOnce();
00276 
00277     ros::Duration(0.1).sleep();
00278 
00279     twist.header.seq++;
00280   }
00281 
00282   EXPECT_LT(::fabs(filtered_.pose.pose.position.y), 0.2);
00283   EXPECT_LT(::fabs(filtered_.pose.pose.position.z + 0.5), 0.2);
00284 
00285   resetFilter();
00286 }
00287 
00288 TEST (InterfacesTest, OdomDifferentialIO)
00289 {
00290   ros::NodeHandle nh;
00291   ros::Publisher odomPub = nh.advertise<nav_msgs::Odometry>("/odom_input1", 5);
00292   ros::Subscriber filteredSub = nh.subscribe("/odometry/filtered", 1, &filterCallback);
00293 
00294   nav_msgs::Odometry odom;
00295   odom.pose.pose.position.x = 20.0;
00296   odom.pose.pose.position.y = 10.0;
00297   odom.pose.pose.position.z = -40.0;
00298 
00299   odom.pose.covariance[0] = 2.0;
00300   odom.pose.covariance[7] = 2.0;
00301   odom.pose.covariance[14] = 2.0;
00302 
00303   odom.pose.pose.orientation.w = 1;
00304 
00305   odom.pose.covariance[21] = 0.2;
00306   odom.pose.covariance[28] = 0.2;
00307   odom.pose.covariance[35] = 0.2;
00308 
00309   odom.header.frame_id = "odom";
00310   odom.child_frame_id = "base_link";
00311 
00312   // No guaranteeing that the zero state
00313   // we're expecting to see here isn't just
00314   // a result of zeroing it out previously,
00315   // so check 10 times in succession.
00316   size_t zeroCount = 0;
00317   while(zeroCount++ < 10)
00318   {
00319     odom.header.stamp = ros::Time::now();
00320     odomPub.publish(odom);
00321     ros::spinOnce();
00322 
00323     EXPECT_EQ(filtered_.pose.pose.position.x, 0);
00324     EXPECT_EQ(filtered_.pose.pose.position.y, 0);
00325     EXPECT_EQ(filtered_.pose.pose.position.z, 0);
00326     EXPECT_EQ(filtered_.pose.pose.orientation.x, 0);
00327     EXPECT_EQ(filtered_.pose.pose.orientation.y, 0);
00328     EXPECT_EQ(filtered_.pose.pose.orientation.z, 0);
00329     EXPECT_EQ(filtered_.pose.pose.orientation.w, 1);
00330 
00331     ros::Duration(0.1).sleep();
00332 
00333     odom.header.seq++;
00334   }
00335 
00336   // Now feed it a position that is near the first
00337   // one. As this sensor is differential, its position
00338   // variables should yield values close to (1, 2, -3)
00339   odom.pose.pose.position.x = 21;
00340   odom.pose.pose.position.y = 12.0;
00341   odom.pose.pose.position.z = -43.0;
00342 
00343   // ...but only if we give the measurement a tiny covariance
00344   for(size_t ind = 0; ind < 36; ind+=7)
00345   {
00346     odom.pose.covariance[ind] = 1e-6;
00347   }
00348 
00349   bool poseChanged = false;
00350 
00351   while(!poseChanged)
00352   {
00353     odom.header.stamp = ros::Time::now();
00354     odomPub.publish(odom);
00355 
00356     ros::spinOnce();
00357 
00358     poseChanged = (::fabs(filtered_.pose.pose.position.x - 1) < 1e-4) &&
00359                   (::fabs(filtered_.pose.pose.position.y - 2) < 1e-4) &&
00360                   (::fabs(filtered_.pose.pose.position.z + 3) < 1e-4) &&
00361                   (filtered_.pose.pose.orientation.x == 0) &&
00362                   (filtered_.pose.pose.orientation.y == 0) &&
00363                   (filtered_.pose.pose.orientation.z == 0) &&
00364                   (filtered_.pose.pose.orientation.w == 1);
00365 
00366     ros::Duration(0.1).sleep();
00367     odom.header.seq++;
00368   }
00369 
00370   poseChanged = false;
00371 
00372   resetFilter();
00373 }
00374 
00375 TEST (InterfacesTest, PoseDifferentialIO)
00376 {
00377   ros::NodeHandle nh;
00378   ros::Publisher posePub = nh.advertise<geometry_msgs::PoseWithCovarianceStamped>("/pose_input1", 5);
00379   ros::Subscriber filteredSub = nh.subscribe("/odometry/filtered", 1, &filterCallback);
00380 
00381   geometry_msgs::PoseWithCovarianceStamped pose;
00382   pose.pose.pose.position.x = 20.0;
00383   pose.pose.pose.position.y = 10.0;
00384   pose.pose.pose.position.z = -40.0;
00385   pose.pose.pose.orientation.x = 0;
00386   pose.pose.pose.orientation.y = 0;
00387   pose.pose.pose.orientation.z = 0;
00388   pose.pose.pose.orientation.w = 1;
00389 
00390   for(size_t ind = 0; ind < 36; ind+=7)
00391   {
00392     pose.pose.covariance[ind] = 1e-6;
00393   }
00394 
00395   pose.header.frame_id = "odom";
00396 
00397   bool poseChanged = false;
00398 
00399   // No guaranteeing that the zero state
00400   // we're expecting to see here isn't just
00401   // a result of zeroing it out previously,
00402   // so check 10 times in succession.
00403   size_t zeroCount = 0;
00404   while(zeroCount++ < 10)
00405   {
00406     pose.header.stamp = ros::Time::now();
00407     posePub.publish(pose);
00408     pose.header.seq++;
00409     ros::spinOnce();
00410 
00411     EXPECT_EQ(filtered_.pose.pose.position.x, 0);
00412     EXPECT_EQ(filtered_.pose.pose.position.y, 0);
00413     EXPECT_EQ(filtered_.pose.pose.position.z, 0);
00414     EXPECT_EQ(filtered_.pose.pose.orientation.x, 0);
00415     EXPECT_EQ(filtered_.pose.pose.orientation.y, 0);
00416     EXPECT_EQ(filtered_.pose.pose.orientation.z, 0);
00417     EXPECT_EQ(filtered_.pose.pose.orientation.w, 1);
00418 
00419     ros::Duration(0.1).sleep();
00420   }
00421 
00422   resetFilter();
00423 }
00424 
00425 int main(int argc, char **argv)
00426 {
00427   testing::InitGoogleTest(&argc, argv);
00428 
00429   ros::init(argc, argv, "ekf_navigation_node-test-interfaces");
00430   ros::Time::init();
00431 
00432   // Give ekf_localization_node time to initialize
00433   ros::Duration(2.0).sleep();
00434 
00435   return RUN_ALL_TESTS();
00436 }


robot_localization
Author(s): Tom Moore
autogenerated on Mon Oct 6 2014 04:11:15