2d_ndt_mcl_node.cpp
Go to the documentation of this file.
00001 
00020 #define USE_VISUALIZATION_DEBUG ///< Enable / Disable visualization
00021 
00022 
00023  
00024 #include <mrpt/utils/CTicTac.h>
00025 
00026 #ifdef USE_VISUALIZATION_DEBUG
00027         #include <mrpt/gui.h>   
00028         #include <mrpt/base.h>
00029         #include <mrpt/opengl.h>
00030         #include <GL/gl.h>
00031         #include "ndt_mcl/CMyEllipsoid.h"
00032 #endif
00033 
00034 #include <ros/ros.h>
00035 #include <rosbag/bag.h>
00036 #include <rosbag/view.h>
00037 #include <tf/transform_listener.h>
00038 #include <boost/foreach.hpp>
00039 #include <sensor_msgs/LaserScan.h>
00040 #include <message_filters/subscriber.h>
00041 #include <message_filters/sync_policies/approximate_time.h>
00042 #include <nav_msgs/Odometry.h>
00043 #include <nav_msgs/OccupancyGrid.h>
00044 #include <visualization_msgs/MarkerArray.h>
00045 #include <tf/transform_broadcaster.h>
00046 #include "geometry_msgs/PoseWithCovarianceStamped.h"
00047 #include "geometry_msgs/Pose.h"
00048 
00049 #include "ndt_mcl/impl/ndt_mcl.hpp"
00050 #include <ndt_map/ndt_map.h>
00051 
00052 
00053 
00057 #ifdef USE_VISUALIZATION_DEBUG
00058 #include "ndt_mcl/impl/mcl_visualization.hpp" 
00059 #endif
00060 ros::Publisher ndtmap_pub; 
00061 
00065 void sendMapToRviz(lslgeneric::NDTMap<pcl::PointXYZ> &map){
00066 
00067         std::vector<lslgeneric::NDTCell<pcl::PointXYZ>*> ndts;
00068         ndts = map.getAllCells();
00069         fprintf(stderr,"SENDING MARKER ARRAY MESSAGE (%lu components)\n",ndts.size());
00070         visualization_msgs::MarkerArray marray;
00071         
00072         for(unsigned int i=0;i<ndts.size();i++){
00073                 Eigen::Matrix3d cov = ndts[i]->getCov();
00074                 Eigen::Vector3d m = ndts[i]->getMean();
00075                 
00076                 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> Sol (cov);
00077 
00078     Eigen::Matrix3d evecs;
00079     Eigen::Vector3d evals;
00080 
00081     evecs = Sol.eigenvectors().real();
00082     evals = Sol.eigenvalues().real();
00083     
00084     Eigen::Quaternion<double> q(evecs);
00085         
00086                 visualization_msgs::Marker marker;
00087                 marker.header.frame_id = "world";
00088                 marker.header.stamp = ros::Time();
00089                 marker.ns = "NDT";
00090                 marker.id = i;
00091                 marker.type = visualization_msgs::Marker::SPHERE;
00092                 marker.action = visualization_msgs::Marker::ADD;
00093                 marker.pose.position.x = m[0];
00094                 marker.pose.position.y = m[1];
00095                 marker.pose.position.z = m[2];
00096                 
00097                 marker.pose.orientation.x = q.x();
00098                 marker.pose.orientation.y = q.y();
00099                 marker.pose.orientation.z = q.z();
00100                 marker.pose.orientation.w = q.w();
00101                 
00102                 marker.scale.x = 100.0*evals(0);
00103                 marker.scale.y = 100.0*evals(1);
00104                 marker.scale.z = 100.0*evals(2);
00105                 /*
00106                 marker.pose.orientation.x = 0;
00107                 marker.pose.orientation.y = 0;
00108                 marker.pose.orientation.z = 0;
00109                 marker.pose.orientation.w = 1;
00110 
00111                 marker.scale.x = 1;
00112                 marker.scale.y = 1;
00113                 marker.scale.z = 1;
00114         */      
00115                 
00116                 marker.color.a = 1.0;
00117                 marker.color.r = 0.0;
00118                 marker.color.g = 1.0;
00119                 marker.color.b = 0.0;
00120                 
00121                 marray.markers.push_back(marker);
00122         }
00123         
00124         ndtmap_pub.publish(marray);
00125         
00126         for(unsigned int i=0;i<ndts.size();i++){
00127                 delete ndts[i];
00128         }
00129 
00130 }
00131 
00132 
00133 
00134 /*
00135  * enter code here
00136 (eigValues,eigVectors) = numpy.linalg.eig (covMat)
00137 
00138 eigx_n=-PyKDL.Vector(eigVectors[0,0],eigVectors[1,0],eigVectors[2,0])
00139 eigy_n=-PyKDL.Vector(eigVectors[0,1],eigVectors[1,1],eigVectors[2,1])
00140 eigz_n=-PyKDL.Vector(eigVectors[0,2],eigVectors[1,2],eigVectors[2,2])
00141 
00142 rot = PyKDL.Rotation (eigx_n,eigy_n,eigz_n)
00143 quat = rot.GetQuaternion ()
00144 
00145 #painting the Gaussian Ellipsoid Marker
00146 marker.pose.orientation.x =quat[0]
00147 marker.pose.orientation.y = quat[1]
00148 marker.pose.orientation.z = quat[2]
00149 marker.pose.orientation.w = quat[3]
00150 marker.scale.x = eigValues[0]
00151 marker.scale.y = eigValues[1]
00152 marker.scale.z =eigValues[2]
00153 */ 
00154 
00155 
00159 bool userInitialPose = false;
00160 bool hasNewInitialPose = false;
00161 
00162 double ipos_x=0,ipos_y=0,ipos_yaw=0;
00163 double ivar_x=0,ivar_y=0,ivar_yaw=0;
00164 
00165 ros::Subscriber initial_pose_sub_;
00166 
00167 void initialPoseReceived(const geometry_msgs::PoseWithCovarianceStampedConstPtr& msg){
00168         tf::Pose ipose;
00169   tf::poseMsgToTF(msg->pose.pose, ipose);
00170   ipos_x = ipose.getOrigin().x();
00171   ipos_y = ipose.getOrigin().y();
00172   double pitch, roll;
00173   ipose.getBasis().getEulerYPR(ipos_yaw,pitch,roll);
00174   
00175   ivar_x = msg->pose.covariance[0];
00176   ivar_x = msg->pose.covariance[6];
00177   ivar_x = msg->pose.covariance[35];
00178   
00179   hasNewInitialPose=true;
00180 }
00181 
00182 
00183 
00184 
00187 
00190 Eigen::Affine3d getAsAffine(float x, float y, float yaw ){
00191         Eigen::Matrix3d m;
00192         m = Eigen::AngleAxisd(0, Eigen::Vector3d::UnitX())
00193                         * Eigen::AngleAxisd(0, Eigen::Vector3d::UnitY())
00194                         * Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ());
00195         Eigen::Translation3d v(x,y,0);
00196         Eigen::Affine3d T = v*m;
00197         
00198         return T;
00199 }
00200 
00210 NDTMCL<pcl::PointXYZ> *ndtmcl;
00212 float offx = 0;
00213 float offy = 0;
00214 float offa = 0;
00215 static bool has_sensor_offset_set = false;
00216 static bool isFirstLoad=true;
00217 Eigen::Affine3d Told,Todo;
00218 
00219 ros::Publisher mcl_pub; 
00220 
00221 
00222 
00223 
00224 
00225 bool sendROSOdoMessage(Eigen::Vector3d mean,Eigen::Matrix3d cov, ros::Time ts){
00226         nav_msgs::Odometry O;
00227         static int seq = 0;
00228         O.header.stamp = ts;
00229         O.header.seq = seq;
00230         O.header.frame_id = "/world";
00231         O.child_frame_id = "/mcl_pose";
00232         
00233         O.pose.pose.position.x = mean[0];
00234         O.pose.pose.position.y = mean[1];
00235         tf::Quaternion q;
00236         q.setRPY(0,0,mean[2]);
00237         O.pose.pose.orientation.x = q.getX();
00238         O.pose.pose.orientation.y = q.getY();
00239         O.pose.pose.orientation.z = q.getZ();
00240         O.pose.pose.orientation.w = q.getW();
00241         
00242 
00251         O.pose.covariance[0] = cov(0,0);
00252         O.pose.covariance[1] = cov(0,1);
00253         O.pose.covariance[2] = 0;
00254         O.pose.covariance[3] = 0;
00255         O.pose.covariance[4] = 0;
00256         O.pose.covariance[5] = 0;
00257         
00258         O.pose.covariance[6] = cov(1,0);
00259         O.pose.covariance[7] = cov(1,1);
00260         O.pose.covariance[8] = 0;
00261         O.pose.covariance[9] = 0;
00262         O.pose.covariance[10] = 0;
00263         O.pose.covariance[11] = 0;
00264         
00265         O.pose.covariance[12] = 0;
00266         O.pose.covariance[13] = 0;
00267         O.pose.covariance[14] = 0;
00268         O.pose.covariance[15] = 0;
00269         O.pose.covariance[16] = 0;
00270         O.pose.covariance[17] = 0;
00271         
00272         O.pose.covariance[18] = 0;
00273         O.pose.covariance[19] = 0;
00274         O.pose.covariance[20] = 0;
00275         O.pose.covariance[21] = 0;
00276         O.pose.covariance[22] = 0;
00277         O.pose.covariance[23] = 0;
00278         
00279         O.pose.covariance[24] = 0;
00280         O.pose.covariance[25] = 0;
00281         O.pose.covariance[26] = 0;
00282         O.pose.covariance[27] = 0;
00283         O.pose.covariance[28] = 0;
00284         O.pose.covariance[29] = 0;
00285         
00286         O.pose.covariance[30] = 0;
00287         O.pose.covariance[31] = 0;
00288         O.pose.covariance[32] = 0;
00289         O.pose.covariance[33] = 0;
00290         O.pose.covariance[34] = 0;
00291         O.pose.covariance[35] = cov(2,2);
00292         
00293         seq++;
00294         mcl_pub.publish(O);
00295         
00296         static tf::TransformBroadcaster br;
00297   tf::Transform transform;
00298   transform.setOrigin( tf::Vector3(mean[0],mean[1], 0.0) );
00299   
00300         transform.setRotation( q );
00301   br.sendTransform(tf::StampedTransform(transform, ts, "world", "mcl_pose"));
00302         
00303         return true;
00304 }
00305 
00306 
00307 
00312 mrpt::utils::CTicTac    TT;
00313 
00314 std::string tf_odo_topic =   "odom_base_link";
00315 std::string tf_state_topic = "base_link";
00316 std::string tf_laser_link =  "base_laser_link";
00317 
00321 void callback(const sensor_msgs::LaserScan::ConstPtr& scan)
00322 {
00323         static int counter = 0;
00324         counter++;
00325         
00326         static tf::TransformListener tf_listener;
00327         double looptime = TT.Tac();
00328         TT.Tic();
00329         fprintf(stderr,"Lt( %.1lfms %.1lfHz seq:%d) -",looptime*1000,1.0/looptime,scan->header.seq);
00330         
00331         if(has_sensor_offset_set == false) return;
00332         double gx,gy,gyaw,x,y,yaw;
00333         
00335         tf::StampedTransform transform;
00336         tf_listener.waitForTransform("world", tf_state_topic, scan->header.stamp,ros::Duration(1.0));
00338         try{
00339                 tf_listener.lookupTransform("world", tf_state_topic, scan->header.stamp, transform);
00340                 gyaw = tf::getYaw(transform.getRotation());  
00341           gx = transform.getOrigin().x();
00342           gy = transform.getOrigin().y();
00343         }
00344         catch (tf::TransformException ex){
00345                 ROS_ERROR("%s",ex.what());
00346                 return;
00347         }
00348         
00350         try{
00351                 tf_listener.lookupTransform("world", tf_odo_topic, scan->header.stamp, transform);
00352                 yaw = tf::getYaw(transform.getRotation());  
00353           x = transform.getOrigin().x();
00354           y = transform.getOrigin().y();
00355         }
00356         catch (tf::TransformException ex){
00357                 ROS_ERROR("%s",ex.what());
00358                 return;
00359         }
00360         
00361                 
00362         mrpt::utils::CTicTac    tictac;
00363         tictac.Tic();
00364         
00366         int N =(scan->angle_max - scan->angle_min)/scan->angle_increment;
00370         
00371         Eigen::Affine3d T = getAsAffine(x,y,yaw);
00372         Eigen::Affine3d Tgt = getAsAffine(gx,gy,gyaw);
00373         
00374         if(userInitialPose && hasNewInitialPose){
00375                 gx = ipos_x;
00376                 gy = ipos_y;
00377                 gyaw = ipos_yaw;
00378         }
00379         
00380         if(isFirstLoad || hasNewInitialPose){
00381                 fprintf(stderr,"Initializing to (%lf, %lf, %lf)\n",gx,gy,gyaw);
00383                 ndtmcl->initializeFilter(gx, gy,gyaw,0.2, 0.2, 2.0*M_PI/180.0, 150);
00384                 Told = T;
00385                 Todo = Tgt;
00386                 hasNewInitialPose = false;
00387         }
00388         
00390         Eigen::Affine3d Tmotion = Told.inverse() * T;
00391         Todo = Todo*Tmotion; 
00392         
00393         if(isFirstLoad==false){
00394                 if( (Tmotion.translation().norm()<0.005 && fabs(Tmotion.rotation().eulerAngles(0,1,2)[2])<(0.2*M_PI/180.0))){
00395                         Eigen::Vector3d dm = ndtmcl->getMean();
00396                         Eigen::Matrix3d cov = ndtmcl->pf.getDistributionVariances();
00397                         sendROSOdoMessage(dm,cov, scan->header.stamp);
00398                         double Time = tictac.Tac();
00399                         fprintf(stderr,"Time elapsed %.1lfms\n",Time*1000);
00400                         return;
00401                 }
00402         }
00403         
00404         Told = T;
00405         
00407         float dy =offy;
00408         float dx = offx;
00409         float alpha = atan2(dy,dx);
00410         float L = sqrt(dx*dx+dy*dy);
00411         
00413         float lpx = L * cos(alpha);
00414         float lpy = L * sin(alpha);
00415         float lpa = offa;
00416         
00418         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); 
00419         for (int j=0;j<N;j++){
00420                 double r  = scan->ranges[j];
00421                 if(r>=scan->range_min && r<scan->range_max && r>0.3 && r<20.0){
00422                         double a  = scan->angle_min + j*scan->angle_increment;
00423                         pcl::PointXYZ pt;
00424                         pt.x = r*cos(a+lpa)+lpx;
00425                         pt.y = r*sin(a+lpa)+lpy;
00426                         pt.z = 0.1+0.02 * (double)rand()/(double)RAND_MAX;
00427                         cloud->push_back(pt);
00428                 }
00429         }
00433         ndtmcl->updateAndPredict(Tmotion, *cloud); 
00434         
00435         Eigen::Vector3d dm = ndtmcl->getMean(); 
00436         Eigen::Matrix3d cov = ndtmcl->pf.getDistributionVariances(); 
00437 
00438         double Time = tictac.Tac();
00439         fprintf(stderr,"Time elapsed %.1lfms (%lf %lf %lf) \n",Time*1000,dm[0],dm[1],dm[2]);
00440         isFirstLoad = false;
00442         
00443         sendROSOdoMessage(dm,cov, scan->header.stamp); 
00444         
00445         if(counter%50==0){
00446                 sendMapToRviz(ndtmcl->map);
00447         }
00448         
00450 #ifdef USE_VISUALIZATION_DEBUG
00451         Eigen::Vector3d origin(dm[0] + L * cos(dm[2]+alpha),dm[1] + L * sin(dm[2]+alpha),0.1);
00452         Eigen::Affine3d ppos = getAsAffine(dm[0],dm[1],dm[2]);
00453         
00454         //lslgeneric::transformPointCloudInPlace(Tgt, *cloud);
00455         lslgeneric::transformPointCloudInPlace(ppos, *cloud);
00456         mrpt::opengl::COpenGLScenePtr &scene = win3D.get3DSceneAndLock();       
00457         win3D.setCameraPointingToPoint(gx,gy,1);
00458         if(counter%2000==0) gl_points->clear();
00459         scene->clear();
00460         scene->insert(plane);
00461         
00462         addMap2Scene(ndtmcl->map, origin, scene);
00463         addPoseCovariance(dm[0],dm[1],cov,scene);
00464         addScanToScene(scene, origin, cloud);
00465         addParticlesToWorld(ndtmcl->pf,Tgt.translation(),dm, Todo.translation());
00466         scene->insert(gl_points);
00467         scene->insert(gl_particles);
00468         win3D.unlockAccess3DScene();
00469         win3D.repaint();
00470 
00471         if (win3D.keyHit())
00472         {
00473                 mrpt::gui::mrptKeyModifier kmods;
00474                 int key = win3D.getPushedKey(&kmods);
00475         }
00476 #endif
00477 }
00478 
00479 
00480 int main(int argc, char **argv){
00481         ros::init(argc, argv, "NDT-MCL");
00482         double resolution=0.4;
00483         
00484 #ifdef USE_VISUALIZATION_DEBUG  
00485         initializeScene();
00486 #endif
00487 
00488         ros::NodeHandle n;
00489         ros::NodeHandle nh;
00490         ros::NodeHandle paramHandle ("~");
00491         TT.Tic();
00492         
00493         std::string tf_base_link,input_laser_topic; 
00494         
00500         bool loadMap = false; 
00501         std::string mapName("basement.ndmap"); 
00502         
00503         bool saveMap = true;                                            
00504         std::string output_map_name = std::string("ndt_mapper_output.ndmap");
00505         
00511         
00512         paramHandle.param<std::string>("input_laser_topic", input_laser_topic, std::string("/base_scan"));
00513         paramHandle.param<std::string>("tf_base_link", tf_state_topic, std::string("/base_link"));
00514         paramHandle.param<std::string>("tf_laser_link", tf_laser_link, std::string("/hokuyo1_link"));
00515         
00516         bool use_sensor_pose;
00517         paramHandle.param<bool>("use_sensor_pose", use_sensor_pose, false);
00518         double sensor_pose_x, sensor_pose_y, sensor_pose_th;
00519         paramHandle.param<double>("sensor_pose_x", sensor_pose_x, 0.);
00520         paramHandle.param<double>("sensor_pose_y", sensor_pose_y, 0.);
00521         paramHandle.param<double>("sensor_pose_th", sensor_pose_th, 0.);
00522         
00523         paramHandle.param<bool>("load_map_from_file", loadMap, false);
00524         paramHandle.param<std::string>("map_file_name", mapName, std::string("basement.ndmap"));
00525         
00526         paramHandle.param<bool>("save_output_map", saveMap, true);
00527         paramHandle.param<std::string>("output_map_file_name", output_map_name, std::string("ndt_mapper_output.ndmap"));
00528         
00529         paramHandle.param<double>("map_resolution", resolution , 0.2);
00530         bool forceSIR=false;
00531         paramHandle.param<bool>("forceSIR", forceSIR, false);
00532                 
00533         paramHandle.param<bool>("set_initial_pose", userInitialPose, false);
00534         paramHandle.param<double>("initial_pose_x", ipos_x, 0.);
00535         paramHandle.param<double>("initial_pose_y", ipos_y, 0.);
00536         paramHandle.param<double>("initial_pose_yaw", ipos_yaw, 0.);
00537         
00538         if(userInitialPose==true) hasNewInitialPose=true;
00539         
00545         fprintf(stderr,"USING RESOLUTION %lf\n",resolution);
00546         lslgeneric::NDTMap<pcl::PointXYZ> ndmap(new lslgeneric::LazyGrid<pcl::PointXYZ>(resolution));
00547 
00548         ndmap.setMapSize(80.0, 80.0, 1.0);
00549         
00550         if(loadMap){
00551                 fprintf(stderr,"Loading Map from '%s'\n",mapName.c_str());
00552                 ndmap.loadFromJFF(mapName.c_str());
00553         }
00554         
00555         ndtmcl = new NDTMCL<pcl::PointXYZ>(resolution,ndmap,-0.5);
00556         if(forceSIR) ndtmcl->forceSIR=true;
00557 
00558         fprintf(stderr,"*** FORCE SIR = %d****",forceSIR);
00564         mcl_pub = nh.advertise<nav_msgs::Odometry>("ndt_mcl",10);
00570         ros::Subscriber scansub=nh.subscribe(input_laser_topic, 1, callback);
00571         
00572         ndtmap_pub = nh.advertise<visualization_msgs::MarkerArray>( "NDTMAP", 0 );
00573         
00574         initial_pose_sub_ = nh.subscribe("initialpose", 1, initialPoseReceived);
00575 
00576         offa = sensor_pose_th;
00577         offx = sensor_pose_x;
00578         offy = sensor_pose_y;
00579         
00580         
00581         has_sensor_offset_set = true;
00582         
00583         fprintf(stderr,"Sensor Pose = (%lf %lf %lf)\n",offx, offy, offa);       
00584         
00585         ros::spin();
00586 
00587         
00588         return 0;
00589 }


ndt_mcl
Author(s): Jari Saarinen
autogenerated on Mon Oct 6 2014 03:20:03