3d_ndt_mcl_node.cpp
Go to the documentation of this file.
00001 
00019 #include <ndt_visualisation/ndt_viz.h>
00020 
00021 #include <ros/ros.h>
00022 #include <tf/transform_listener.h>
00023 #include <boost/foreach.hpp>
00024 #include <sensor_msgs/LaserScan.h>
00025 #include <message_filters/subscriber.h>
00026 #include <message_filters/sync_policies/approximate_time.h>
00027 #include <nav_msgs/Odometry.h>
00028 #include <nav_msgs/OccupancyGrid.h>
00029 #include <visualization_msgs/MarkerArray.h>
00030 #include <tf/transform_broadcaster.h>
00031 #include "geometry_msgs/PoseWithCovarianceStamped.h"
00032 #include "geometry_msgs/Pose.h"
00033 #include <pcl_conversions/pcl_conversions.h>
00034 
00035 #include "message_filters/subscriber.h"
00036 #include "tf/message_filter.h"
00037 #include <tf/transform_broadcaster.h>
00038 #include <tf_conversions/tf_eigen.h>
00039 #include <message_filters/subscriber.h>
00040 #include <message_filters/synchronizer.h>
00041 #include <message_filters/sync_policies/approximate_time.h>
00042 #include <nav_msgs/Odometry.h>
00043 #include <geometry_msgs/PoseStamped.h>
00044 
00045 #include "sensor_msgs/PointCloud2.h"
00046 
00047 //#include "ndt_mcl/impl/ndt_mcl.hpp"
00048 #include "ndt_mcl/3d_ndt_mcl.h"
00049 #include <ndt_map/ndt_map.h>
00050 
00051 #define SYNC_FRAMES 20
00052 
00053 typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::PointCloud2, nav_msgs::Odometry> PointsOdomSync;
00054 //TODO typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::PointCloud2, geometry_msgs::PoseStamped> PointsPoseSync;
00055 
00056 class NDTMCL3DNode {
00057 
00058     private:
00059         ros::NodeHandle nh_;
00060         NDTMCL3D *ndtmcl;
00061         boost::mutex mcl_m,message_m;
00062 
00063         message_filters::Subscriber<sensor_msgs::PointCloud2> *points2_sub_;
00064         message_filters::Subscriber<nav_msgs::Odometry> *odom_sub_;
00065 
00067         Eigen::Affine3d sensorPoseT; //<<Sensor offset with respect to odometry frame
00068         Eigen::Affine3d Told,Todo,Todo_old,Tcum; //<<old and current odometry transformations
00069         Eigen::Affine3d initPoseT; //<<Sensor offset with respect to odometry frame
00070 
00071         bool hasSensorPose, hasInitialPose;
00072         bool isFirstLoad;
00073         bool forceSIR, do_visualize;
00074         bool saveMap;                                           
00075         std::string mapName; 
00076         std::string output_map_name;
00077         double resolution;
00078         double subsample_level;
00079         int pcounter;
00080         NDTViz ndt_viz;
00081 
00082         ros::Publisher mcl_pub; 
00083         message_filters::Synchronizer< PointsOdomSync > *sync_po_;
00084 
00085         std::string tf_base_link, tf_sensor_link, points_topic, odometry_topic;
00086     public:
00087         NDTMCL3DNode(ros::NodeHandle param_nh) {
00088             
00089 
00093             bool use_sensor_pose, use_initial_pose;
00094             double pose_init_x,pose_init_y,pose_init_z,
00095                    pose_init_r,pose_init_p,pose_init_t;
00096             double sensor_pose_x,sensor_pose_y,sensor_pose_z,
00097                    sensor_pose_r,sensor_pose_p,sensor_pose_t;
00098 
00099             param_nh.param<bool>("set_sensor_pose", use_sensor_pose, true);
00100             param_nh.param<bool>("set_initial_pose", use_initial_pose, false);
00101             
00102             if(use_initial_pose) {
00104                 param_nh.param("pose_init_x",pose_init_x,0.);
00105                 param_nh.param("pose_init_y",pose_init_y,0.);
00106                 param_nh.param("pose_init_z",pose_init_z,0.);
00107                 param_nh.param("pose_init_r",pose_init_r,0.);
00108                 param_nh.param("pose_init_p",pose_init_p,0.);
00109                 param_nh.param("pose_init_t",pose_init_t,0.);
00110                 initPoseT =  Eigen::Translation<double,3>(pose_init_x,pose_init_y,pose_init_z)*
00111                     Eigen::AngleAxis<double>(pose_init_r,Eigen::Vector3d::UnitX()) *
00112                     Eigen::AngleAxis<double>(pose_init_p,Eigen::Vector3d::UnitY()) *
00113                     Eigen::AngleAxis<double>(pose_init_t,Eigen::Vector3d::UnitZ()) ;
00114 
00115                 hasInitialPose=true;
00116             } else {
00117                 hasInitialPose=false;
00118             }
00119 
00120             if(use_sensor_pose) {
00122                 param_nh.param("sensor_pose_x",sensor_pose_x,0.);
00123                 param_nh.param("sensor_pose_y",sensor_pose_y,0.);
00124                 param_nh.param("sensor_pose_z",sensor_pose_z,0.);
00125                 param_nh.param("sensor_pose_r",sensor_pose_r,0.);
00126                 param_nh.param("sensor_pose_p",sensor_pose_p,0.);
00127                 param_nh.param("sensor_pose_t",sensor_pose_t,0.);
00128                 hasSensorPose = true;
00129                 sensorPoseT =  Eigen::Translation<double,3>(sensor_pose_x,sensor_pose_y,sensor_pose_z)*
00130                     Eigen::AngleAxis<double>(sensor_pose_r,Eigen::Vector3d::UnitX()) *
00131                     Eigen::AngleAxis<double>(sensor_pose_p,Eigen::Vector3d::UnitY()) *
00132                     Eigen::AngleAxis<double>(sensor_pose_t,Eigen::Vector3d::UnitZ()) ;
00133             } else {
00134                 hasSensorPose = false;
00135             }
00136 
00140             param_nh.param<std::string>("map_file_name", mapName, std::string("basement.ndmap"));
00141             param_nh.param<bool>("save_output_map", saveMap, true);
00142             param_nh.param<bool>("do_visualize", do_visualize, true);
00143             param_nh.param<std::string>("output_map_file_name", output_map_name, std::string("ndt_mapper_output.ndmap"));
00144             param_nh.param<double>("map_resolution", resolution , 0.2);
00145             param_nh.param<double>("subsample_level", subsample_level , 1);
00146 
00147             fprintf(stderr,"USING RESOLUTION %lf\n",resolution);
00148             
00149             lslgeneric::NDTMap ndmap(new lslgeneric::LazyGrid(resolution));
00150             ndmap.loadFromJFF(mapName.c_str());
00151 
00155 
00156             ndtmcl = new NDTMCL3D(resolution,ndmap,-5);
00157             param_nh.param<bool>("forceSIR", forceSIR, false);
00158             if(forceSIR) ndtmcl->forceSIR=true;
00159 
00160             fprintf(stderr,"*** FORCE SIR = %d****",forceSIR);
00161             mcl_pub = nh_.advertise<nav_msgs::Odometry>("ndt_mcl",10);
00162             
00166             //the name of the TF link associated to the base frame / odometry frame    
00167             param_nh.param<std::string>("tf_base_link", tf_base_link, std::string("/base_link"));
00168             //the name of the tf link associated to the 3d laser scanner
00169             param_nh.param<std::string>("tf_laser_link", tf_sensor_link, std::string("/velodyne_link"));
00171             param_nh.param<std::string>("points_topic",points_topic,"points");
00173             param_nh.param<std::string>("odometry_topic",odometry_topic,"odometry");
00174 
00175             points2_sub_ = new message_filters::Subscriber<sensor_msgs::PointCloud2>(nh_,points_topic,1);
00176             odom_sub_ = new message_filters::Subscriber<nav_msgs::Odometry>(nh_,odometry_topic,10);
00177             sync_po_ = new message_filters::Synchronizer< PointsOdomSync >(PointsOdomSync(SYNC_FRAMES), *points2_sub_, *odom_sub_);
00178             sync_po_->registerCallback(boost::bind(&NDTMCL3DNode::callback, this, _1, _2));
00179 
00180             isFirstLoad=true;
00181             pcounter =0;
00182         }
00183         ~NDTMCL3DNode() {
00184             delete points2_sub_;
00185             delete odom_sub_;
00186             delete sync_po_;
00187             delete ndtmcl;
00188         }
00190         //new callback: looks up transforms on TF
00191         void callback(const sensor_msgs::PointCloud2::ConstPtr& cloud_in,
00192                 const nav_msgs::Odometry::ConstPtr& odo_in)
00193         {
00194             mcl_m.lock();
00195             //compute new odo and point cloud
00196             Eigen::Quaterniond qd;
00197             Eigen::Affine3d Tm;
00198             pcl::PointCloud<pcl::PointXYZ> cloud, cloudT, cloudTO;
00199             
00200             qd.x() = odo_in->pose.pose.orientation.x;
00201             qd.y() = odo_in->pose.pose.orientation.y;
00202             qd.z() = odo_in->pose.pose.orientation.z;
00203             qd.w() = odo_in->pose.pose.orientation.w;
00204 
00205             Todo = Eigen::Translation3d (odo_in->pose.pose.position.x,
00206                     odo_in->pose.pose.position.y,odo_in->pose.pose.position.z) * qd;
00207             
00208             pcl::fromROSMsg (*cloud_in, cloud);
00209             
00210             fprintf(stderr,"cloud has %d points\n",cloud.points.size());                
00211             //check if sensor pose is known, if not, look it up on TF
00212             if(!hasSensorPose) {
00213 
00214             }
00215             //check if we have done iterations 
00216             if(isFirstLoad) {
00217                 //if not, check if initial robot pose has been set
00218                 if(!hasInitialPose) {
00219                     //can't do anything, wait for pose message...
00220                     mcl_m.unlock();
00221                     return;
00222                 }
00223                 //initialize filter
00224                 Eigen::Vector3d tr = initPoseT.translation();
00225                 Eigen::Vector3d rot = initPoseT.rotation().eulerAngles(0,1,2);
00226                 
00227                 Todo_old=Todo;
00228                 Tcum = initPoseT;
00229 
00230                 ndtmcl->initializeFilter(tr[0], tr[1],tr[2],rot[0],rot[1],rot[2],0.5, 0.5, 0.1, 2.0*M_PI/180.0, 2.0*M_PI/180.0 ,2.0*M_PI/180.0, 100);
00231                 //ndt_viz.plotNDTMap(&ndtmcl->map,0,1.0,1.0,true, false); 
00232                 ndt_viz.plotNDTSAccordingToOccupancy(-1,&ndtmcl->map);
00233                 isFirstLoad = false;
00234                 mcl_m.unlock();
00235                 return;
00236             }
00237             
00238             Tm = Todo_old.inverse()*Todo;
00239             if(Tm.translation().norm()<0.01 && fabs(Tm.rotation().eulerAngles(0,1,2)[2])<(0.5*M_PI/180.0)) {
00240                 mcl_m.unlock();
00241                 return;
00242             }
00243             
00244             Tcum = Tcum*Tm;
00245             Todo_old=Todo;
00246 
00247             //cut off user defined slice form the sensor data
00248             //transform point cloud from sensor pose into base pose
00249     
00251             lslgeneric::transformPointCloudInPlace(sensorPoseT, cloud);
00252             //cloudT = lslgeneric::transformPointCloud(Tcum, cloud);
00253 
00254             //update filter -> + add parameter to subsample ndt map in filter step
00255             ndtmcl->updateAndPredictEff(Tm, cloud, subsample_level);
00256 
00257 
00258             //update visualization
00260             if(do_visualize) {
00261                 pcounter++;
00262                 if(pcounter%500==0){
00263                     ndt_viz.clear();
00264                     ndt_viz.plotNDTSAccordingToOccupancy(-1,&ndtmcl->map);
00265 
00266                 }
00267 
00268                 //if(pcounter%10==0){
00269 
00270                 ndt_viz.clearParticles();
00271                 for(int i=0;i<ndtmcl->pf.size();i++){
00272                     double x,y,z;
00273                     ndtmcl->pf.pcloud[i].getXYZ(x,y,z);
00274                     ndt_viz.addParticle(x, y,z+0.5, 1.0, 1.0, 1.0);
00275                 }
00276 
00277                 Eigen::Affine3d mean = ndtmcl->pf.getMean();
00278                 ndt_viz.addTrajectoryPoint(mean.translation()[0],mean.translation()[1],mean.translation()[2]+0.5,1.0,0,0);      
00279                 Eigen::Vector3d tr = Tcum.translation();
00280                 ndt_viz.addTrajectoryPoint(tr[0],tr[1],tr[2]+0.5,0.0,1.0,0);    
00281 
00282                 //ndt_viz.addPointCloud(cloudT,1,0,0);
00283                 ndt_viz.displayParticles();
00284                 ndt_viz.displayTrajectory();
00285                 ndt_viz.win3D->setCameraPointingToPoint(mean.translation()[0],mean.translation()[1],3.0);
00286                 ndt_viz.repaint();
00287                 //}
00288             }
00289             //publish pose
00290             sendROSOdoMessage(ndtmcl->pf.getMean(),odo_in->header.stamp);
00291             mcl_m.unlock();
00292 
00293         }
00295         //FIXME: this should be in 3D
00297         bool sendROSOdoMessage(Eigen::Affine3d mean,ros::Time ts){
00298             nav_msgs::Odometry O;
00299             static int seq = 0;
00300             O.header.stamp = ts;
00301             O.header.seq = seq;
00302             O.header.frame_id = "/world";
00303             O.child_frame_id = "/mcl_pose";
00304 
00305             O.pose.pose.position.x = mean.translation()[0];
00306             O.pose.pose.position.y = mean.translation()[1];
00307             O.pose.pose.position.z = mean.translation()[2];
00308             Eigen::Quaterniond q (mean.rotation());
00309             tf::Quaternion qtf;
00310             tf::quaternionEigenToTF (q, qtf);
00311             O.pose.pose.orientation.x = q.x();
00312             O.pose.pose.orientation.y = q.y();
00313             O.pose.pose.orientation.z = q.z();
00314             O.pose.pose.orientation.w = q.w();
00315 
00316             seq++;
00317             mcl_pub.publish(O);
00318 
00319             static tf::TransformBroadcaster br;
00320             tf::Transform transform;
00321             transform.setOrigin( tf::Vector3(mean.translation()[0],mean.translation()[1], mean.translation()[2]) );
00322 
00323             transform.setRotation( qtf );
00324             br.sendTransform(tf::StampedTransform(transform, ts, "world", "mcl_pose"));
00325 
00326             return true;
00327         }
00329 };
00330 
00331 
00332 int main(int argc, char **argv){
00333         ros::init(argc, argv, "NDT-MCL");
00334         ros::NodeHandle paramHandle ("~");
00335         NDTMCL3DNode mclnode(paramHandle);      
00336         ros::spin();
00337         return 0;
00338 }


ndt_mcl
Author(s): Jari Saarinen
autogenerated on Wed Aug 26 2015 15:25:02