Quellcode durchsuchen

定位/制图 ,loop增加icp/ndt匹配选项,增加keyFrame,未完成,先提交

zx vor 1 Jahr
Ursprung
Commit
c9d90d9997

+ 1 - 1
CMakeLists.txt

@@ -109,6 +109,6 @@ catkin_package(
 
 add_library(ikd_Tree include/ikd-Tree/ikd_Tree.cpp)
 add_library(preprocess  src/preprocess.cpp)
-add_executable(fastlio_sam_mapping src/laserMapping.cpp src/scancontext/Scancontext.cpp)
+add_executable(fastlio_sam_mapping src/laserMapping.cpp src/scancontext/Scancontext.cpp src/keyFramesManager.cpp src/keyFramesManager.h)
 target_link_libraries(fastlio_sam_mapping ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${PYTHON_LIBRARIES}  ikd_Tree preprocess gtsam)  #${GeographicLib_LIBRARIES}
 target_include_directories(fastlio_sam_mapping PRIVATE ${PYTHON_INCLUDE_DIRS})

Datei-Diff unterdrückt, da er zu groß ist
+ 27 - 1231
Log/mat_pre.txt


+ 9 - 6
config/horizon.yaml

@@ -7,7 +7,7 @@ preprocess:
     lidar_type: 1              # 1 for Livox serials LiDAR, 2 for Velodyne LiDAR, 3 for ouster LiDAR, 
     scan_line:  6
     blind: 2                   #4m  point distance<blind   ignored
-
+max_iteration: 10
 mapping:
     acc_cov: 0.1
     gyr_cov: 0.1
@@ -22,7 +22,7 @@ mapping:
                    0, 0, 1]
 
 publish:
-    path_en:  false
+    path_en:  true
     scan_publish_en:  true       # false: close all the point cloud output
     dense_publish_en: false       # false: low down the points number in a global-frame point clouds scan.
     scan_bodyframe_pub_en: false  # true: output the point cloud scans in IMU-body-frame
@@ -62,7 +62,7 @@ surroundingKeyframeSize: 50                   # submap size (when loop closure e
 historyKeyframeSearchRadius: 1.5             # meters, key frame that is within n meters from current pose will be considerd for loop closure
 historyKeyframeSearchTimeDiff: 30.0           # seconds, key frame that is n seconds older will be considered for loop closure
 historyKeyframeSearchNum: 20                  # number of hostory key frames will be fused into a submap for loop closure
-historyKeyframeFitnessScore: 0.3              # icp threshold, the smaller the better alignment
+historyKeyframeFitnessScore: 0.25             # icp threshold, the smaller the better alignment
 
 # Visualization
 globalMapVisualizationSearchRadius: 1000.0    # meters, global map visualization radius
@@ -70,15 +70,18 @@ globalMapVisualizationPoseDensity: 10      # meters, global map visualization ke
 globalMapVisualizationLeafSize: 1.0           # meters, global map visualization cloud density
 
 # visual iktree_map  
-locate_mode: true
-locate_map: "/home/zx/Downloads/LOAM2/filterGlobalMap.pcd"  #"/home/zx/doc/ros_ws/map/open_road/filterGlobalMap.pcd"  #/home/zx/Downloads/LOAM2
 visulize_IkdtreeMap: true
 
 # visual iktree_map  
 recontructKdTree: true
 
 # Export settings
+ndtLoopMatch: true  # false -- icp
+locate_mode: true
+locate:
+    init_pos: [-7.129,2.5,0]
+    init_rpy: [0,0,0.00]
 savePCD: true                         # https://github.com/TixiaoShan/LIO-SAM/issues/3
-savePCDDirectory: "/Downloads/LOAM2/"        # in your home folder, starts and ends with "/". Warning: the code deletes "LOAM" folder then recreates it. See "mapOptimization" for implementation
+savePCDDirectory: "/doc/ros_ws/map/zkxy_livox"        # in your home folder, starts and ends with "/". Warning: the code deletes "LOAM" folder then recreates it. See "mapOptimization" for implementation
 
 

+ 1 - 0
config/large_velodyne.yaml

@@ -20,6 +20,7 @@ preprocess:
     scan_line: 16
     scan_rate: 10                # only need to be set for velodyne, unit: Hz,
     blind: 1
+point_filter_num: 1
 
 mapping:
     acc_cov: 3.9939570888238808e-03

+ 3 - 41
include/IKFoM_toolkit/esekfom/esekfom.hpp

@@ -1617,7 +1617,7 @@ public:
 	}
 	
 	//iterated error state EKF update modified for one specific system.
-	void update_iterated_dyn_share_modified(double R, double &solve_time) {
+	bool update_iterated_dyn_share_modified(double R, double &solve_time) {
 		
 		dyn_share_datastruct<scalar_type> dyn_share;
 		dyn_share.valid = true;
@@ -1701,21 +1701,6 @@ public:
 					P_. template block<1, 2>(i, idx) = (P_. template block<1, 2>(i, idx)) * res_temp_S2.transpose();
 				}
 			}
-			//Matrix<scalar_type, n, Eigen::Dynamic> K_;
-			//Matrix<scalar_type, n, 1> K_h;
-			//Matrix<scalar_type, n, n> K_x; 
-
-			/*
-			if(n > dof_Measurement)
-			{
-				K_= P_ * h_x_.transpose() * (h_x_ * P_ * h_x_.transpose()/R + Eigen::Matrix<double, Dynamic, Dynamic>::Identity(dof_Measurement, dof_Measurement)).inverse()/R;
-			}
-			else
-			{
-				K_= (h_x_.transpose() * h_x_ + (P_/R).inverse()).inverse()*h_x_.transpose();
-			}
-			*/
-
             // 如果状态量维度大于观测方程 n > m,不满秩
 			if(n > dof_Measurement)
 			{
@@ -1836,7 +1821,6 @@ public:
 			{
 				dyn_share.converge = true;
 			}
-
             // 最后一次迭代更新协方差矩阵
 			if(t > 1 || i == maximum_iter - 1)
 			{
@@ -1906,35 +1890,13 @@ public:
 					}
 				}
 
-				// if(n > dof_Measurement)
-				// {
-				// 	Eigen::Matrix<scalar_type, Eigen::Dynamic, Eigen::Dynamic> h_x_cur = Eigen::Matrix<scalar_type, Eigen::Dynamic, Eigen::Dynamic>::Zero(dof_Measurement, n);
-				// 	h_x_cur.topLeftCorner(dof_Measurement, 12) = h_x_;
-				// 	/*
-				// 	h_x_cur.col(0) = h_x_.col(0);
-				// 	h_x_cur.col(1) = h_x_.col(1);
-				// 	h_x_cur.col(2) = h_x_.col(2);
-				// 	h_x_cur.col(3) = h_x_.col(3);
-				// 	h_x_cur.col(4) = h_x_.col(4);
-				// 	h_x_cur.col(5) = h_x_.col(5);
-				// 	h_x_cur.col(6) = h_x_.col(6);
-				// 	h_x_cur.col(7) = h_x_.col(7);
-				// 	h_x_cur.col(8) = h_x_.col(8);
-				// 	h_x_cur.col(9) = h_x_.col(9);
-				// 	h_x_cur.col(10) = h_x_.col(10);
-				// 	h_x_cur.col(11) = h_x_.col(11);
-				// 	*/
-				// 	P_ = L_ - K_*h_x_cur * P_;
-				// }
-				// else
-				//{
 					P_ = L_ - K_x.template block<n, 12>(0, 0) * P_.template block<12, n>(0, 0);
-				//}
 				solve_time += omp_get_wtime() - solve_start;
-				return;
+				return dyn_share.converge;
 			}
 			solve_time += omp_get_wtime() - solve_start;
 		}
+    return dyn_share.converge;
 	}
 
 	void change_x(state &input_state)

+ 8 - 8
rviz_cfg/loam_livox.rviz

@@ -90,7 +90,7 @@ Visualization Manager:
           Position Transformer: XYZ
           Queue Size: 1
           Selectable: false
-          Size (Pixels): 2
+          Size (Pixels): 3
           Size (m): 0.05000000074505806
           Style: Points
           Topic: /cloud_registered
@@ -346,7 +346,7 @@ Visualization Manager:
   Views:
     Current:
       Class: rviz/Orbit
-      Distance: 634.8995971679688
+      Distance: 105.75137329101562
       Enable Stereo Rendering:
         Stereo Eye Separation: 0.05999999865889549
         Stereo Focal Distance: 1
@@ -354,9 +354,9 @@ Visualization Manager:
         Value: false
       Field of View: 0.7853981852531433
       Focal Point:
-        X: 47.004695892333984
-        Y: 117.68125915527344
-        Z: -65.06320190429688
+        X: 0.25273245573043823
+        Y: 0.24122393131256104
+        Z: -65.51172637939453
       Focal Shape Fixed Size: true
       Focal Shape Size: 0.05000000074505806
       Invert Z Axis: false
@@ -364,7 +364,7 @@ Visualization Manager:
       Near Clip Distance: 0.009999999776482582
       Pitch: 1.5697963237762451
       Target Frame: global
-      Yaw: 1.6305780410766602
+      Yaw: 3.110581159591675
     Saved: ~
 Window Geometry:
   Displays:
@@ -382,5 +382,5 @@ Window Geometry:
   Views:
     collapsed: true
   Width: 1359
-  X: 0
-  Y: 75
+  X: -273
+  Y: 58

+ 56 - 0
src/keyFramesManager.cpp

@@ -0,0 +1,56 @@
+//
+// Created by zx on 23-8-4.
+//
+
+#include "keyFramesManager.h"
+#include <pcl/common/transforms.h>
+keyFrame::keyFrame(PointCloudXYZI::Ptr cloud) {
+  cloud_=cloud;
+  cloud_world_.reset(new PointCloudXYZI());
+  pose_changed_=true;
+}
+keyFrame::keyFrame(PointTypePose pose, PointCloudXYZI::Ptr cloud) {
+  cloud_=cloud;
+  cloud_world_.reset(new PointCloudXYZI());
+  pose_changed_=true;
+
+}
+keyFrame::~keyFrame() {}
+
+void keyFrame::ResetPose(PointTypePose pose){
+  pose_=pose;
+  pose_changed_=true;
+}
+
+
+PointCloudXYZI::Ptr keyFrame::world_cloud(){
+  if(pose_changed_==false){
+    return cloud_world_;
+  }
+  int cloudSize = cloud_->size();
+  cloud_world_->resize(cloudSize);
+
+  Eigen::Affine3f transCur = pcl::getTransformation(pose_.x, pose_.y, pose_.z, pose_.roll, pose_.pitch, pose_.yaw);
+
+  int numberOfCores=4;
+#pragma omp parallel for num_threads(numberOfCores)
+  for (int i = 0; i < cloudSize; ++i)
+  {
+    const auto &pointFrom = cloud_->points[i];
+    cloud_world_->points[i].x = transCur(0, 0) * pointFrom.x + transCur(0, 1) * pointFrom.y + transCur(0, 2) * pointFrom.z + transCur(0, 3);
+    cloud_world_->points[i].y = transCur(1, 0) * pointFrom.x + transCur(1, 1) * pointFrom.y + transCur(1, 2) * pointFrom.z + transCur(1, 3);
+    cloud_world_->points[i].z = transCur(2, 0) * pointFrom.x + transCur(2, 1) * pointFrom.y + transCur(2, 2) * pointFrom.z + transCur(2, 3);
+    cloud_world_->points[i].intensity = pointFrom.intensity;
+  }
+  pose_changed_=false;
+  return cloud_world_;
+}
+
+pcl::PointCloud<PointTypePose>::Ptr keyFramesManager::GetPoses(){
+  pcl::PointCloud<PointTypePose>::Ptr ret(new pcl::PointCloud<PointTypePose>);
+  ret->resize(frames_.size());
+  for(int i=0;i<frames_.size();++i){
+    ret->points[i]=frames_[i].Pose();
+  }
+  return ret;
+}

+ 36 - 0
src/keyFramesManager.h

@@ -0,0 +1,36 @@
+//
+// Created by zx on 23-8-4.
+//
+
+#ifndef FAST_LIO_SAM_KEYFRAMESMANAGER_H
+#define FAST_LIO_SAM_KEYFRAMESMANAGER_H
+#include "common_lib.h"
+#include "preprocess.h"
+class keyFrame{
+public:
+    keyFrame(PointCloudXYZI::Ptr cloud);
+    keyFrame(PointTypePose pose,PointCloudXYZI::Ptr cloud);
+    ~keyFrame();
+    void ResetPose(PointTypePose pose);
+    PointTypePose Pose(){return pose_;}
+    PointCloudXYZI::Ptr cloud(){return cloud_;}
+    PointCloudXYZI::Ptr world_cloud();
+protected:
+    PointTypePose pose_;
+    PointCloudXYZI::Ptr cloud_;
+    PointCloudXYZI::Ptr cloud_world_;
+    bool pose_changed_;
+};
+
+class keyFramesManager {
+public:
+    keyFramesManager();
+    ~keyFramesManager();
+
+    pcl::PointCloud<PointTypePose>::Ptr GetPoses();
+
+    std::vector<keyFrame> frames_;
+
+};
+
+#endif //FAST_LIO_SAM_KEYFRAMESMANAGER_H

+ 366 - 271
src/laserMapping.cpp

@@ -23,6 +23,7 @@
 #include <tf/transform_datatypes.h>
 #include <tf/transform_broadcaster.h>
 #include <geometry_msgs/Vector3.h>
+#include <geometry_msgs/PoseWithCovarianceStamped.h>          //PoseWithCovarianceStamped
 #include <livox_ros_driver/CustomMsg.h>
 #include "preprocess.h"
 #include <ikd-Tree/ikd_Tree.h>
@@ -43,6 +44,7 @@
 #include <pcl/common/common.h>
 #include <pcl/common/transforms.h>
 #include <pcl/registration/icp.h>
+#include <pcl/registration/ndt.h>
 #include <pcl/io/pcd_io.h>
 #include <pcl/filters/filter.h>
 #include <pcl/filters/crop_box.h>
@@ -63,6 +65,7 @@
 #include <gtsam/inference/Symbol.h>
 #include <gtsam/nonlinear/ISAM2.h>
 
+#include "keyFramesManager.h"
 /*
 // gnss
 #include "GNSS_Processing.hpp"
@@ -147,9 +150,11 @@ V3D Lidar_T_wrt_IMU(Zero3d); // T lidar to imu (imu = r * lidar + t)
 M3D Lidar_R_wrt_IMU(Eye3d);  // R lidar to imu (imu = r * lidar + t)
 
 /*** EKF inputs and output ***/
+std::mutex ikf_lock_;
 MeasureGroup Measures;
 esekfom::esekf<state_ikfom, 12, input_ikfom> ikfom_; // 状态,噪声维度,输入
 state_ikfom state_point;
+state_ikfom last_state_point;
 vect3 pos_lid; // world系下lidar坐标
 
 nav_msgs::Path path;
@@ -254,12 +259,10 @@ float globalMapVisualizationSearchRadius;
 float globalMapVisualizationPoseDensity;
 float globalMapVisualizationLeafSize;
 
-// saveMap
-ros::ServiceServer srvSaveMap;
-ros::ServiceServer srvSavePose;
+
 bool savePCD;               // 是否保存地图
 string savePCDDirectory;    // 保存路径
-
+bool ndt_loop=false;
 /*
  * scancontext 回环检测
  */
@@ -402,29 +405,6 @@ float pointDistance(PointType p1, PointType p2)
     return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) + (p1.z - p2.z) * (p1.z - p2.z));
 }
 
-/**
- * 初始化
- */
-void allocateMemory()
-{
-    cloudKeyPoses3D.reset(new pcl::PointCloud<PointType>());
-    cloudKeyPoses6D.reset(new pcl::PointCloud<PointTypePose>());
-    copy_cloudKeyPoses3D.reset(new pcl::PointCloud<PointType>());
-    copy_cloudKeyPoses6D.reset(new pcl::PointCloud<PointTypePose>());
-
-    kdtreeSurroundingKeyPoses.reset(new pcl::KdTreeFLANN<PointType>());
-    kdtreeHistoryKeyPoses.reset(new pcl::KdTreeFLANN<PointType>());
-
-    laserCloudOri.reset(new pcl::PointCloud<PointType>());
-
-    kdtreeCornerFromMap.reset(new pcl::KdTreeFLANN<PointType>());
-    kdtreeSurfFromMap.reset(new pcl::KdTreeFLANN<PointType>());
-
-    for (int i = 0; i < 6; ++i)
-    {
-        transformTobeMapped[i] = 0;
-    }
-}
 
 //  eulerAngle 2 Quaterniond
 Eigen::Quaterniond  EulerToQuat(float roll_, float pitch_, float yaw_)
@@ -673,7 +653,7 @@ void performLoopClosure() {
 
     loopKeyPre = SCclosestHistoryFrameID;
     loopKeyCur = cloudKeyPoses3D->size() - 1; // because cpp starts 0 and ends n-1
-    cout << "Loop detected! - between " << loopKeyPre << " and " << loopKeyCur << "" << endl;
+    //cout << "Loop detected! - between " << loopKeyPre << " and " << loopKeyCur << "" << endl;
 
   }else{
     return;
@@ -696,7 +676,18 @@ void performLoopClosure() {
       publishCloud(&pubHistoryKeyFrames, prevKeyframeCloud, timeLaserInfoStamp, odometryFrame);
   }
 
+  double icp_t1 = omp_get_wtime();
+  float noiseScore;
+  Eigen::Affine3f correctionLidarFrame;
+  float x, y, z, roll, pitch, yaw;
+  /*PointTypePose current = copy_cloudKeyPoses6D->points[loopKeyCur];
+  PointTypePose target = copy_cloudKeyPoses6D->points[loopKeyPre];
+  gtsam::Pose3 poseSrc(gtsam::Rot3::RzRyRx(double(current.roll), double(current.pitch), double(current.yaw)),
+                       gtsam::Point3(double(current.x), double(current.y), double(current.z)));
+  gtsam::Pose3 poseTar(gtsam::Rot3::RzRyRx(double(target.roll), double(target.pitch), double(target.yaw)),
+                       gtsam::Point3(double(target.x), double(target.y), double(target.z)));*/
   // ICP Settings
+if(ndt_loop==false) {
   pcl::IterativeClosestPoint<PointType, PointType> icp;
   icp.setMaxCorrespondenceDistance(150); // giseop , use a value can cover 2*historyKeyframeSearchNum range in meter
   icp.setMaximumIterations(100);
@@ -709,35 +700,65 @@ void performLoopClosure() {
   icp.setInputTarget(prevKeyframeCloud);
   pcl::PointCloud<PointType>::Ptr unused_result(new pcl::PointCloud<PointType>());
   icp.align(*unused_result);
-
-  // 未收敛,或者匹配不够好
-  if (icp.hasConverged() == false || icp.getFitnessScore() > historyKeyframeFitnessScore)
+  noiseScore =icp.getFitnessScore(); //  loop_clousre  noise from ndt
+  correctionLidarFrame = icp.getFinalTransformation();
+  double icp_t2 = omp_get_wtime();
+  pcl::getTranslationAndEulerAngles(correctionLidarFrame, x, y, z, roll, pitch, yaw);
+  if (icp.hasConverged() == false || icp.getFitnessScore() > historyKeyframeFitnessScore) {
+    printf("icp failed,score:%f from %d to %d ,(%f %f %f) (%f %f %f) time:%f\n",
+           icp.getFitnessScore(),loopKeyCur, loopKeyPre,x, y, z, roll, pitch, yaw,icp_t2 - icp_t1);
     return;
-
-  std::cout << "icp  success  " << std::endl;
+  }
+  printf("icp success,score:%f from %d to %d ,(%f %f %f) (%f %f %f) time:%f\n",
+         icp.getFitnessScore(),loopKeyCur, loopKeyPre,x, y, z, roll, pitch, yaw,icp_t2 - icp_t1);
+
+}else {
+  pcl::NormalDistributionsTransform<PointType, PointType> ndt;
+  ndt.setTransformationEpsilon(0.001);
+  // Setting maximum step size for More-Thuente line search.
+  ndt.setStepSize(0.1);
+  //Setting Resolution of NDT grid structure (VoxelGridCovariance).
+  ndt.setResolution(0.5);
+  // Setting max number of registration iterations.
+  ndt.setMaximumIterations(50);
+  // Setting point cloud to be aligned.
+  ndt.setInputSource(cureKeyframeCloud);
+  // Setting point cloud to be aligned to.
+  ndt.setInputTarget(prevKeyframeCloud);
+  pcl::PointCloud<PointType>::Ptr unused_result(new pcl::PointCloud<PointType>());
+  ndt.align(*unused_result, Eigen::Matrix4f::Identity());
+
+  double icp_t2 = omp_get_wtime();
+  noiseScore =ndt.getFitnessScore(); //  loop_clousre  noise from ndt
+  correctionLidarFrame = ndt.getFinalTransformation();
+  pcl::getTranslationAndEulerAngles(correctionLidarFrame, x, y, z, roll, pitch, yaw);
+  if (ndt.hasConverged() == false || ndt.getFitnessScore() > historyKeyframeFitnessScore) {
+    printf("ndt failed,score:%f from %d to %d ,(%f %f %f) (%f %f %f) time:%f\n",
+           ndt.getFitnessScore(),loopKeyCur, loopKeyPre,x, y, z, roll, pitch, yaw,icp_t2 - icp_t1);
+    return;
+  }
+  printf("ndt success,score:%f from %d to %d ,(%f %f %f) (%f %f %f) time:%f\n",
+         ndt.getFitnessScore(),loopKeyCur, loopKeyPre,x, y, z, roll, pitch, yaw,icp_t2 - icp_t1);
+}
 
   // 发布当前关键帧经过闭环优化后的位姿变换之后的特征点云
   if (pubIcpKeyFrames.getNumSubscribers() != 0) {
     pcl::PointCloud<PointType>::Ptr closed_cloud(new pcl::PointCloud<PointType>());
-    pcl::transformPointCloud(*cureKeyframeCloud, *closed_cloud, icp.getFinalTransformation());
+    pcl::transformPointCloud(*cureKeyframeCloud, *closed_cloud, correctionLidarFrame);
     publishCloud(&pubIcpKeyFrames, closed_cloud, timeLaserInfoStamp, odometryFrame);
   }
 
   // 闭环优化得到的当前关键帧与闭环关键帧之间的位姿变换
-  float x, y, z, roll, pitch, yaw;
-  Eigen::Affine3f correctionLidarFrame;
-  correctionLidarFrame = icp.getFinalTransformation();
-
   // 闭环优化前当前帧位姿
   Eigen::Affine3f tWrong = pclPointToAffine3f(copy_cloudKeyPoses6D->points[loopKeyCur]);
   // 闭环优化后当前帧位姿
   Eigen::Affine3f tCorrect = correctionLidarFrame * tWrong;
-  pcl::getTranslationAndEulerAngles(tCorrect, x, y, z, roll, pitch, yaw); //  获取上一帧 相对 当前帧的 位姿
+  pcl::getTranslationAndEulerAngles(tCorrect, x, y, z, roll, pitch, yaw); //  获取上一帧匹配后的位姿
   gtsam::Pose3 poseFrom = gtsam::Pose3(gtsam::Rot3::RzRyRx(roll, pitch, yaw), gtsam::Point3(x, y, z));
   // 闭环匹配帧的位姿
   gtsam::Pose3 poseTo = pclPointTogtsamPose3(copy_cloudKeyPoses6D->points[loopKeyPre]);
   gtsam::Vector Vector6(6);
-  float noiseScore = icp.getFitnessScore(); //  loop_clousre  noise from icp
+
   Vector6 << noiseScore, noiseScore, noiseScore, noiseScore, noiseScore, noiseScore;
   gtsam::noiseModel::Diagonal::shared_ptr constraintNoise = gtsam::noiseModel::Diagonal::Variances(Vector6);
   std::cout << "loopNoiseQueue   =   " << noiseScore << std::endl;
@@ -762,6 +783,7 @@ void saveKeyFramesAndFactor()
     addOdomFactor();
   scManager.makeAndSaveScancontextAndKeys(*feats_undistort);
   performLoopClosure();   //闭环检测
+  visualizeLoopClosure();//展示闭环边
     // 闭环因子 (rs-loop-detect)  基于欧氏距离的检测
     addLoopFactor();
     // 执行优化
@@ -1906,7 +1928,34 @@ void h_share_model(state_ikfom &s, esekfom::dyn_share_datastruct<double> &ekfom_
     solve_time += omp_get_wtime() - solve_start_;
 }
 
+void init_pose_cbk(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr &msg){
+  double x=msg->pose.pose.position.x;
+  double y=msg->pose.pose.position.y;
+  printf("  received init pose:%f  %f \n",x,y);
+  state_ikfom state_inited;
+  Eigen::Vector3d pos(x,y, 0);
+  Eigen::Quaterniond q(msg->pose.pose.orientation.w,msg->pose.pose.orientation.x,
+                       msg->pose.pose.orientation.y,msg->pose.pose.orientation.z);
+  //  更新状态量
+  state_inited.pos = pos;
+  state_inited.rot =  q;
+
+  double epsi[23] = {0.005};
+  fill(epsi, epsi + 23, 0.005);
+  ///初始化,其中h_share_model定义了·平面搜索和残差计算
+  esekfom::esekf<state_ikfom, 12, input_ikfom> new_ikfom; // 状态,噪声维度,输入
+  new_ikfom.init_dyn_share(get_f, df_dx, df_dw, h_share_model, NUM_MAX_ITERATIONS, epsi);
+  new_ikfom.change_x(state_inited);
+
+  ikf_lock_.lock();
+  ikfom_=new_ikfom;
+  state_point=state_inited;
+  last_state_point=state_inited;
+  p_imu->Reset();
+  flg_first_scan=true;
+  ikf_lock_.unlock();
 
+}
 
 int main(int argc, char **argv) {
   // allocateMemory();
@@ -1921,7 +1970,7 @@ int main(int argc, char **argv) {
   nh.param<bool>("publish/scan_publish_en", scan_pub_en, true);
   nh.param<bool>("publish/dense_publish_en", dense_pub_en, true);
   nh.param<bool>("publish/scan_bodyframe_pub_en", scan_body_pub_en, true);
-  nh.param<int>("max_iteration", NUM_MAX_ITERATIONS, 4);
+  nh.param<int>("max_iteration", NUM_MAX_ITERATIONS, 10);
   nh.param<string>("map_file_path", map_file_path, "");
   nh.param<string>("common/lid_topic", lid_topic, "/livox/lidar");
   nh.param<string>("common/imu_topic", imu_topic, "/livox/imu");
@@ -1940,7 +1989,7 @@ int main(int argc, char **argv) {
   nh.param<int>("preprocess/lidar_type", p_pre->lidar_type, AVIA);
   nh.param<int>("preprocess/scan_line", p_pre->N_SCANS, 16);
   nh.param<int>("preprocess/scan_rate", p_pre->SCAN_RATE, 10);
-  nh.param<int>("point_filter_num", p_pre->point_filter_num, 2);
+  nh.param<int>("point_filter_num", p_pre->point_filter_num, 1);
   nh.param<bool>("feature_extract_enable", p_pre->feature_enabled, false);
   nh.param<bool>("runtime_pos_log_enable", runtime_pos_log, 0);
   nh.param<bool>("mapping/extrinsic_est_en", extrinsic_est_en, true);
@@ -1983,7 +2032,12 @@ int main(int argc, char **argv) {
 
   // visual ikdtree map
   nh.param<bool>("locate_mode", locate_mode, false);
+  vector<double> init_pos(3, 0.0);
+  vector<double> init_rpy(3, 0.0);
+  nh.param<vector<double>>("locate/init_pos", init_pos, vector<double>());
+  nh.param<vector<double>>("locate/init_rpy", init_rpy, vector<double>());
   nh.param<bool>("visulize_IkdtreeMap", visulize_IkdtreeMap, false);
+  nh.param<bool>("ndtLoopMatch", ndt_loop, false);
 
   // reconstruct ikdtree
   nh.param<bool>("recontructKdTree", recontructKdTree, false);
@@ -2091,270 +2145,311 @@ int main(int argc, char **argv) {
       "/fast_lio_sam/mapping/loop_closure_constraints", 1);
 
 
-  // saveMap  发布地图保存服务
-  srvSaveMap = nh.advertiseService("/save_map", &saveMapService);
-
-  // savePose  发布轨迹保存服务
-  srvSavePose = nh.advertiseService("/save_pose", &savePoseService);
-
-
+  ros::Subscriber sub_init_pose;
   // 回环检测线程
-  std::thread* loopthread= nullptr;
-  if (locate_mode == false)
-     loopthread=new std::thread(&loopClosureThread);
-  else{
+  std::thread *loopthread = nullptr;
+  if (locate_mode == false) {
+    ros::ServiceServer srvSaveMap;
+    ros::ServiceServer srvSavePose;
+    // saveMap  发布地图保存服务
+    srvSaveMap = nh.advertiseService("/save_map", &saveMapService);
+    // savePose  发布轨迹保存服务
+    srvSavePose = nh.advertiseService("/save_pose", &savePoseService);
+    loopthread = new std::thread(&loopClosureThread);
+  } else {
     PointCloudXYZI map_cloud;
-    std::string map_file=std::getenv("HOME")+savePCDDirectory+"/filterGlobalMap.pcd";
-    if (pcl::io::loadPCDFile<PointType> (map_file, map_cloud) == -1) //* 读入PCD格式的文件,如果文件不存在,返回-1
+    std::string map_file = std::getenv("HOME") + savePCDDirectory + "/filterGlobalMap.pcd";
+    if (pcl::io::loadPCDFile<PointType>(map_file, map_cloud) == -1) //* 读入PCD格式的文件,如果文件不存在,返回-1
     {
       PCL_ERROR ("Couldn't read file test_pcd.pcd \n"); //文件不存在时,返回错误,终止程序。
       return (-1);
     }
-    printf(" Read map point num:%d\n",map_cloud.size());
+    printf(" Read map point num:%d\n", map_cloud.size());
     ikdtree.Build(map_cloud.points);
-    usleep(1000*1000);
-  }
 
-    //------------------------------------------------------------------------------------------------------
-  if (visulize_IkdtreeMap) // If you need to see map point, change to "if(1)"
-  {
+    sub_init_pose = nh.subscribe("/initialpose", 1000, init_pose_cbk);
+
+    state_ikfom state_inited;
+    Eigen::Vector3d pos(init_pos[0], init_pos[1], init_pos[2]);
+    Eigen::Quaterniond q = EulerToQuat(init_rpy[0], init_rpy[1], init_rpy[2]);
+    //  更新状态量
+    state_inited.pos = pos;
+    state_inited.rot = q;
+    ikfom_.change_x(state_inited);
+    last_state_point = state_inited;
+
+    usleep(1000 * 1000);
     PointVector().swap(ikdtree.PCL_Storage);
     ikdtree.flatten(ikdtree.Root_Node, ikdtree.PCL_Storage, NOT_RECORD);
     featsFromMap->clear();
     featsFromMap->points = ikdtree.PCL_Storage;
     publish_map(pubLaserCloudMap);
   }
-    signal(SIGINT, SigHandle);
-    ros::Rate rate(5000);
-    bool status = ros::ok();
-    while (status)
-    {
-        if (flg_exit)
-            break;
-        ros::spinOnce();
 
-        /// 在Measure内,储存当前lidar数据及lidar扫描时间内对应的imu数据序列
-        if (sync_packages(Measures))
-        {
-            //第一帧lidar数据
-            if (flg_first_scan)
-            {
-                first_lidar_time = Measures.lidar_beg_time; //记录第一帧绝对时间
-                p_imu->first_lidar_time = first_lidar_time; //记录第一帧绝对时间
-                flg_first_scan = false;
-                continue;
-            }
+  signal(SIGINT, SigHandle);
+  ros::Rate rate(5000);
+  bool status = ros::ok();
+  while (status) {
+    if (flg_exit)
+      break;
+    ros::spinOnce();
+
+    /// 在Measure内,储存当前lidar数据及lidar扫描时间内对应的imu数据序列
+    if (sync_packages(Measures)) {
+      ikf_lock_.lock();
+      //第一帧lidar数据
+      if (flg_first_scan) {
+        first_lidar_time = Measures.lidar_beg_time; //记录第一帧绝对时间
+        p_imu->first_lidar_time = first_lidar_time; //记录第一帧绝对时间
+        flg_first_scan = false;
+        ikf_lock_.unlock();
+        continue;
+      }
 
-            double t0, t1, t2, t3, t4, t5, match_start, solve_start, svd_time;
+      double t0, t1, t2, t3, t4, t5, match_start, solve_start, svd_time;
 
-            match_time = 0;
-            kdtree_search_time = 0.0;
-            solve_time = 0;
-            solve_const_H_time = 0;
-            svd_time = 0;
-            t0 = omp_get_wtime();
+      match_time = 0;
+      kdtree_search_time = 0.0;
+      solve_time = 0;
+      solve_const_H_time = 0;
+      svd_time = 0;
+      t0 = omp_get_wtime();
 
-            //根据imu数据序列和lidar数据,向前传播纠正点云的畸变, 此前已经完成间隔采样或特征提取
-            // feats_undistort 为畸变纠正之后的点云,lidar系
-            p_imu->Process(Measures, ikfom_, feats_undistort);
-            state_point = ikfom_.get_x();                                               // 前向传播后body的状态预测值
-            pos_lid = state_point.pos + state_point.rot * state_point.offset_T_L_I; // global系 lidar位置
+      //根据imu数据序列和lidar数据,向前传播纠正点云的畸变, 此前已经完成间隔采样或特征提取
+      // feats_undistort 为畸变纠正之后的点云,lidar系
 
-            if (feats_undistort->empty() || (feats_undistort == NULL))
-            {
-                ROS_WARN("No point, skip this scan!\n");
-                continue;
-            }
+      p_imu->Process(Measures, ikfom_, feats_undistort);
+      state_point = ikfom_.get_x();                                               // 前向传播后body的状态预测值
+      pos_lid = state_point.pos + state_point.rot * state_point.offset_T_L_I; // global系 lidar位置
 
-            // 检查当前lidar数据时间,与最早lidar数据时间是否足够,两帧间隔0.1s
-            flg_EKF_inited = (Measures.lidar_beg_time - first_lidar_time) < INIT_TIME ? false : true;
-
-            /*** Segment the map in lidar FOV ***/
-            if(locate_mode==false)
-              lasermap_fov_segment(); // 根据lidar在W系下的位置,重新确定局部地图的包围盒角点,移除远端的点
-
-            /*** downsample the feature points in a scan ***/
-            downSizeFilterSurf.setInputCloud(feats_undistort);
-            downSizeFilterSurf.filter(*feats_down_body);
-            t1 = omp_get_wtime();
-            feats_down_size = feats_down_body->points.size(); //当前帧降采样后点数
-
-            /*** initialize the map kdtree ***/
-            if(locate_mode==false) {
-              if (ikdtree.Root_Node == nullptr) {
-                if (feats_down_size > 5) {
-                  ikdtree.set_downsample_param(filter_size_map_min);
-                  feats_down_world->resize(feats_down_size);
-                  for (int i = 0; i < feats_down_size; i++) {
-                    pointBodyToWorld(&(feats_down_body->points[i]), &(feats_down_world->points[i])); // point转到world系下
-                  }
-                  // world系下对当前帧降采样后的点云,初始化lkd-tree
-                  ikdtree.Build(feats_down_world->points);
-                }
-                continue;
-              }
-            }
-            int featsFromMapNum = ikdtree.validnum();
-            kdtree_size_st = ikdtree.size();
+      if (feats_undistort->empty() || (feats_undistort == NULL)) {
+        ROS_WARN("No point, skip this scan!\n");
+        ikf_lock_.unlock();
+        continue;
+      }
 
-            // cout<<"[ mapping ]: In num: "<<feats_undistort->points.size()<<" downsamp "<<feats_down_size<<" Map num: "<<featsFromMapNum<<"effect num:"<<effct_feat_num<<endl;
+      // 检查当前lidar数据时间,与最早lidar数据时间是否足够,两帧间隔0.1s
+      flg_EKF_inited = (Measures.lidar_beg_time - first_lidar_time) < INIT_TIME ? false : true;
+
+      /*** Segment the map in lidar FOV ***/
+      if (locate_mode == false)
+        lasermap_fov_segment(); // 根据lidar在W系下的位置,重新确定局部地图的包围盒角点,移除远端的点
+      else {
+        /*** downsample the feature points in a scan ***/
+        double ndt_beg = omp_get_wtime();
+        downSizeFilterSurf.setInputCloud(feats_undistort);
+        downSizeFilterSurf.filter(*feats_down_body);
+
+        pcl::NormalDistributionsTransform<PointType, PointType> ndt;
+        ndt.setTransformationEpsilon(0.001);
+        // Setting maximum step size for More-Thuente line search.
+        ndt.setStepSize(0.1);
+        //Setting Resolution of NDT grid structure (VoxelGridCovariance).
+        ndt.setResolution(0.5);
+        // Setting max number of registration iterations.
+        ndt.setMaximumIterations(50);
+        // Setting point cloud to be aligned.
+        ndt.setInputSource(feats_down_body);
+        // Setting point cloud to be aligned to.
+        ndt.setInputTarget(featsFromMap);
+        pcl::PointCloud<PointType>::Ptr unused_result(new pcl::PointCloud<PointType>());
+        ndt.align(*unused_result, Eigen::Matrix4f::Identity());
+        double ndt_end = omp_get_wtime();
+
+        printf(" ndt time :%f , size(%d  %d)\n", ndt_end - ndt_beg, feats_down_body->size(), featsFromMap->size());
 
-            /*** ICP and iterated Kalman filter update ***/
-            if (feats_down_size < 5)
-            {
-                ROS_WARN("No point, skip this scan!\n");
-                continue;
-            }
+      }
 
-            normvec->resize(feats_down_size);
-            feats_down_world->resize(feats_down_size);
+      t1 = omp_get_wtime();
+      feats_down_size = feats_down_body->points.size(); //当前帧降采样后点数
 
-            // lidar --> imu
-            V3D ext_euler = SO3ToEuler(state_point.offset_R_L_I);
-            fout_pre << setw(20) << Measures.lidar_beg_time - first_lidar_time << " " << euler_cur.transpose() << " " << state_point.pos.transpose() << " " << ext_euler.transpose() << " " << state_point.offset_T_L_I.transpose() << " " << state_point.vel.transpose()
-                     << " " << state_point.bg.transpose() << " " << state_point.ba.transpose() << " " << state_point.grav << endl;
-
-
-
-            pointSearchInd_surf.resize(feats_down_size);
-            Nearest_Points.resize(feats_down_size);
-            int rematch_num = 0;
-            bool nearest_search_en = true; //
-
-            t2 = omp_get_wtime();
-
-            /*** iterated state estimation ***/
-            double t_update_start = omp_get_wtime();
-            double solve_H_time = 0;
-            ikfom_.update_iterated_dyn_share_modified(LASER_POINT_COV, solve_H_time); //预测、更新
-            state_point = ikfom_.get_x();
-            euler_cur = SO3ToEuler(state_point.rot);
-            pos_lid = state_point.pos + state_point.rot * state_point.offset_T_L_I; // world系下lidar坐标
-            geoQuat.x = state_point.rot.coeffs()[0];                                // world系下当前imu的姿态四元数
-            geoQuat.y = state_point.rot.coeffs()[1];
-            geoQuat.z = state_point.rot.coeffs()[2];
-            geoQuat.w = state_point.rot.coeffs()[3];
-
-            double t_update_end = omp_get_wtime();
-
-            getCurPose(state_point); //   更新transformTobeMapped
-            /*back end*/
-            // 1.计算当前帧与前一帧位姿变换,如果变化太小,不设为关键帧,反之设为关键帧
-            // 2.添加激光里程计因子、GPS因子、闭环因子
-            // 3.执行因子图优化
-            // 4.得到当前帧优化后的位姿,位姿协方差
-            // 5.添加cloudKeyPoses3D,cloudKeyPoses6D,更新transformTobeMapped,添加当前关键帧的角点、平面点集合
-            if(locate_mode==false) {
-              saveKeyFramesAndFactor();
-              // 更新因子图中所有变量节点的位姿,也就是所有历史关键帧的位姿,更新里程计轨迹, 重构ikdtree
-              correctPoses();
+      /*** initialize the map kdtree ***/
+      if (locate_mode == false) {
+        if (ikdtree.Root_Node == nullptr) {
+          if (feats_down_size > 5) {
+            ikdtree.set_downsample_param(filter_size_map_min);
+            feats_down_world->resize(feats_down_size);
+            for (int i = 0; i < feats_down_size; i++) {
+              pointBodyToWorld(&(feats_down_body->points[i]), &(feats_down_world->points[i])); // point转到world系下
             }
-          double tloop = omp_get_wtime();
-          printf(" match time:%fs,kdtree points:%d  save KeyFrame loop time:%fs\n",t_update_end-t_update_start,
-                 ikdtree.validnum(),tloop-t_update_end);
-            /******* Publish odometry *******/
-            publish_odometry(pubOdomAftMapped);
-            /*** add the feature points to map kdtree ***/
-
-
-          if(locate_mode==false) {
-            t3 = omp_get_wtime();
-            map_incremental();
-            t5 = omp_get_wtime();
+            // world系下对当前帧降采样后的点云,初始化lkd-tree
+            ikdtree.Build(feats_down_world->points);
           }
-            // Publish points
-          if (scan_pub_en)
-            publish_frame_world(pubLaserCloudFull);        //   发布world系下的点云
-
-            if (path_en){
-                publish_path(pubPath);
-                publish_path_update(pubPathUpdate);             //   发布经过isam2优化后的路径
-                static int jjj = 0;
-                jjj++;
-                if (jjj % 100 == 0)
-                {
-                    publishGlobalMap();             //  发布局部点云特征地图
-                }
-            }
+          ikf_lock_.unlock();
+          continue;
+        }
+      }
+      int featsFromMapNum = ikdtree.validnum();
+      kdtree_size_st = ikdtree.size();
 
-            if (scan_pub_en && scan_body_pub_en)
-                publish_frame_body(pubLaserCloudFull_body);         //  发布imu系下的点云
+      // cout<<"[ mapping ]: In num: "<<feats_undistort->points.size()<<" downsamp "<<feats_down_size<<" Map num: "<<featsFromMapNum<<"effect num:"<<effct_feat_num<<endl;
 
-            /*
-            //Debug variables
-            if (runtime_pos_log)
-            {
-                frame_num++;
-                kdtree_size_end = ikdtree.size();
-                aver_time_consu = aver_time_consu * (frame_num - 1) / frame_num + (t5 - t0) / frame_num;
-                aver_time_icp = aver_time_icp * (frame_num - 1) / frame_num + (t_update_end - t_update_start) / frame_num;
-                aver_time_match = aver_time_match * (frame_num - 1) / frame_num + (match_time) / frame_num;
-                aver_time_incre = aver_time_incre * (frame_num - 1) / frame_num + (kdtree_incremental_time) / frame_num;
-                aver_time_solve = aver_time_solve * (frame_num - 1) / frame_num + (solve_time + solve_H_time) / frame_num;
-                aver_time_const_H_time = aver_time_const_H_time * (frame_num - 1) / frame_num + solve_time / frame_num;
-                T1[time_log_counter] = Measures.lidar_beg_time;
-                s_plot[time_log_counter] = t5 - t0;
-                s_plot2[time_log_counter] = feats_undistort->points.size();
-                s_plot3[time_log_counter] = kdtree_incremental_time;
-                s_plot4[time_log_counter] = kdtree_search_time;
-                s_plot5[time_log_counter] = kdtree_delete_counter;
-                s_plot6[time_log_counter] = kdtree_delete_time;
-                s_plot7[time_log_counter] = kdtree_size_st;
-                s_plot8[time_log_counter] = kdtree_size_end;
-                s_plot9[time_log_counter] = aver_time_consu;
-                s_plot10[time_log_counter] = add_point_size;
-                time_log_counter++;
-                printf("[ mapping ]: time: IMU + Map + Input Downsample: %0.6f ave match: %0.6f ave solve: %0.6f  ave ICP: %0.6f  map incre: %0.6f ave total: %0.6f icp: %0.6f construct H: %0.6f \n", t1 - t0, aver_time_match, aver_time_solve, t3 - t1, t5 - t3, aver_time_consu, aver_time_icp, aver_time_const_H_time);
-                ext_euler = SO3ToEuler(state_point.offset_R_L_I);
-                fout_out << setw(20) << Measures.lidar_beg_time - first_lidar_time << " " << euler_cur.transpose() << " " << state_point.pos.transpose() << " " << ext_euler.transpose() << " " << state_point.offset_T_L_I.transpose() << " " << state_point.vel.transpose()
-                         << " " << state_point.bg.transpose() << " " << state_point.ba.transpose() << " " << state_point.grav << " " << feats_undistort->points.size() << endl;
-                dump_lio_state_to_log(fp);
-            }*/
+      /*** ICP and iterated Kalman filter update ***/
+      if (feats_down_size < 5) {
+        ROS_WARN("No point, skip this scan!\n");
+        ikf_lock_.unlock();
+        continue;
+      }
+
+      normvec->resize(feats_down_size);
+      feats_down_world->resize(feats_down_size);
+
+      // lidar --> imu
+      V3D ext_euler = SO3ToEuler(state_point.offset_R_L_I);
+      fout_pre << setw(20) << Measures.lidar_beg_time - first_lidar_time << " " << euler_cur.transpose() << " "
+               << state_point.pos.transpose() << " " << ext_euler.transpose() << " "
+               << state_point.offset_T_L_I.transpose() << " " << state_point.vel.transpose()
+               << " " << state_point.bg.transpose() << " " << state_point.ba.transpose() << " " << state_point.grav
+               << endl;
+
+      pointSearchInd_surf.resize(feats_down_size);
+      Nearest_Points.resize(feats_down_size);
+      int rematch_num = 0;
+      bool nearest_search_en = true; //
+
+      t2 = omp_get_wtime();
+
+      /*** iterated state estimation ***/
+      double t_update_start = omp_get_wtime();
+      double solve_H_time = 0;
+      bool matched = ikfom_.update_iterated_dyn_share_modified(LASER_POINT_COV, solve_H_time);//预测、更新
+      state_point = ikfom_.get_x();
+      last_state_point = state_point;
+      /*if (matched==false && locate_mode==true) {
+        printf(" ikfom state update failed ...continue...\n");
+        ikfom_.change_x(last_state_point);//恢复到前一帧的数据
+        state_point = last_state_point;
+      }*/
+
+      euler_cur = SO3ToEuler(state_point.rot);
+      pos_lid = state_point.pos + state_point.rot * state_point.offset_T_L_I; // world系下lidar坐标
+      geoQuat.x = state_point.rot.coeffs()[0];                                // world系下当前imu的姿态四元数
+      geoQuat.y = state_point.rot.coeffs()[1];
+      geoQuat.z = state_point.rot.coeffs()[2];
+      geoQuat.w = state_point.rot.coeffs()[3];
+      double t_update_end = omp_get_wtime();
+      getCurPose(state_point); //   更新transformTobeMapped
+      // Publish points
+      if (scan_pub_en) {
+        publish_frame_world(pubLaserCloudFull);        //   发布world系下的点云
+      }
+      /******* Publish odometry *******/
+      publish_odometry(pubOdomAftMapped);
+      ikf_lock_.unlock();
+      /*if (matched == false && locate_mode==true) {
+        continue;
+      }*/
+
+      /*back end*/
+      // 1.计算当前帧与前一帧位姿变换,如果变化太小,不设为关键帧,反之设为关键帧
+      // 2.添加激光里程计因子、GPS因子、闭环因子
+      // 3.执行因子图优化
+      // 4.得到当前帧优化后的位姿,位姿协方差
+      // 5.添加cloudKeyPoses3D,cloudKeyPoses6D,更新transformTobeMapped,添加当前关键帧的角点、平面点集合
+      if (locate_mode == false) {
+        saveKeyFramesAndFactor();
+        // 更新因子图中所有变量节点的位姿,也就是所有历史关键帧的位姿,更新里程计轨迹, 重构ikdtree
+        correctPoses();
+      }
+      double tloop = omp_get_wtime();
+      /*printf(" match time:%fs,kdtree points:%d  save KeyFrame loop time:%fs\n", t_update_end - t_update_start,
+             ikdtree.validnum(), tloop - t_update_end);*/
+
+      /*** add the feature points to map kdtree ***/
+      if (locate_mode == false) {
+        t3 = omp_get_wtime();
+        map_incremental();
+        t5 = omp_get_wtime();
+      }
+
+      if (path_en) {
+        publish_path(pubPath);
+        publish_path_update(pubPathUpdate);             //   发布经过isam2优化后的路径
+        static int jjj = 0;
+        jjj++;
+        if (jjj % 100 == 0) {
+          publishGlobalMap();             //  发布局部点云特征地图
         }
+      }
 
-        status = ros::ok();
-        rate.sleep();
-    }
+      if (scan_pub_en && scan_body_pub_en)
+        publish_frame_body(pubLaserCloudFull_body);         //  发布imu系下的点云
 
-    /**************** save map ****************/
-    /* 1. make sure you have enough memories
-    /* 2. pcd save will largely influence the real-time performences **/
-    if (pcl_wait_save->size() > 0 && pcd_save_en)
-    {
-        string file_name = string("scans.pcd");
-        string all_points_dir(string(string(ROOT_DIR) + "PCD/") + file_name);
-        pcl::PCDWriter pcd_writer;
-        cout << "current scan saved to /PCD/" << file_name << endl;
-        pcd_writer.writeBinary(all_points_dir, *pcl_wait_save);
+      /*
+      //Debug variables
+      if (runtime_pos_log)
+      {
+          frame_num++;
+          kdtree_size_end = ikdtree.size();
+          aver_time_consu = aver_time_consu * (frame_num - 1) / frame_num + (t5 - t0) / frame_num;
+          aver_time_icp = aver_time_icp * (frame_num - 1) / frame_num + (t_update_end - t_update_start) / frame_num;
+          aver_time_match = aver_time_match * (frame_num - 1) / frame_num + (match_time) / frame_num;
+          aver_time_incre = aver_time_incre * (frame_num - 1) / frame_num + (kdtree_incremental_time) / frame_num;
+          aver_time_solve = aver_time_solve * (frame_num - 1) / frame_num + (solve_time + solve_H_time) / frame_num;
+          aver_time_const_H_time = aver_time_const_H_time * (frame_num - 1) / frame_num + solve_time / frame_num;
+          T1[time_log_counter] = Measures.lidar_beg_time;
+          s_plot[time_log_counter] = t5 - t0;
+          s_plot2[time_log_counter] = feats_undistort->points.size();
+          s_plot3[time_log_counter] = kdtree_incremental_time;
+          s_plot4[time_log_counter] = kdtree_search_time;
+          s_plot5[time_log_counter] = kdtree_delete_counter;
+          s_plot6[time_log_counter] = kdtree_delete_time;
+          s_plot7[time_log_counter] = kdtree_size_st;
+          s_plot8[time_log_counter] = kdtree_size_end;
+          s_plot9[time_log_counter] = aver_time_consu;
+          s_plot10[time_log_counter] = add_point_size;
+          time_log_counter++;
+          printf("[ mapping ]: time: IMU + Map + Input Downsample: %0.6f ave match: %0.6f ave solve: %0.6f  ave ICP: %0.6f  map incre: %0.6f ave total: %0.6f icp: %0.6f construct H: %0.6f \n", t1 - t0, aver_time_match, aver_time_solve, t3 - t1, t5 - t3, aver_time_consu, aver_time_icp, aver_time_const_H_time);
+          ext_euler = SO3ToEuler(state_point.offset_R_L_I);
+          fout_out << setw(20) << Measures.lidar_beg_time - first_lidar_time << " " << euler_cur.transpose() << " " << state_point.pos.transpose() << " " << ext_euler.transpose() << " " << state_point.offset_T_L_I.transpose() << " " << state_point.vel.transpose()
+                   << " " << state_point.bg.transpose() << " " << state_point.ba.transpose() << " " << state_point.grav << " " << feats_undistort->points.size() << endl;
+          dump_lio_state_to_log(fp);
+      }*/
     }
 
-    fout_out.close();
-    fout_pre.close();
+    status = ros::ok();
+    rate.sleep();
+  }
 
-    if (runtime_pos_log)
-    {
-        vector<double> t, s_vec, s_vec2, s_vec3, s_vec4, s_vec5, s_vec6, s_vec7;
-        FILE *fp2;
-        string log_dir = root_dir + "/Log/fast_lio_time_log.csv";
-        fp2 = fopen(log_dir.c_str(), "w");
-        fprintf(fp2, "time_stamp, total time, scan point size, incremental time, search time, delete size, delete time, tree size st, tree size end, add point size, preprocess time\n");
-        for (int i = 0; i < time_log_counter; i++)
-        {
-            fprintf(fp2, "%0.8f,%0.8f,%d,%0.8f,%0.8f,%d,%0.8f,%d,%d,%d,%0.8f\n", T1[i], s_plot[i], int(s_plot2[i]), s_plot3[i], s_plot4[i], int(s_plot5[i]), s_plot6[i], int(s_plot7[i]), int(s_plot8[i]), int(s_plot10[i]), s_plot11[i]);
-            t.push_back(T1[i]);
-            s_vec.push_back(s_plot9[i]);
-            s_vec2.push_back(s_plot3[i] + s_plot6[i]);
-            s_vec3.push_back(s_plot4[i]);
-            s_vec5.push_back(s_plot[i]);
-        }
-        fclose(fp2);
-    }
+  /**************** save map ****************/
+  /* 1. make sure you have enough memories
+  /* 2. pcd save will largely influence the real-time performences **/
+  if (pcl_wait_save->size() > 0 && pcd_save_en) {
+    string file_name = string("scans.pcd");
+    string all_points_dir(string(string(ROOT_DIR) + "PCD/") + file_name);
+    pcl::PCDWriter pcd_writer;
+    cout << "current scan saved to /PCD/" << file_name << endl;
+    pcd_writer.writeBinary(all_points_dir, *pcl_wait_save);
+  }
 
-    startFlag = false;
-    if(locate_mode==false) {
-      loopthread->join(); //  分离线程
+  fout_out.close();
+  fout_pre.close();
+
+  if (runtime_pos_log) {
+    vector<double> t, s_vec, s_vec2, s_vec3, s_vec4, s_vec5, s_vec6, s_vec7;
+    FILE *fp2;
+    string log_dir = root_dir + "/Log/fast_lio_time_log.csv";
+    fp2 = fopen(log_dir.c_str(), "w");
+    fprintf(fp2,
+            "time_stamp, total time, scan point size, incremental time, search time, delete size, delete time, tree size st, tree size end, add point size, preprocess time\n");
+    for (int i = 0; i < time_log_counter; i++) {
+      fprintf(fp2, "%0.8f,%0.8f,%d,%0.8f,%0.8f,%d,%0.8f,%d,%d,%d,%0.8f\n", T1[i], s_plot[i], int(s_plot2[i]),
+              s_plot3[i], s_plot4[i], int(s_plot5[i]), s_plot6[i], int(s_plot7[i]), int(s_plot8[i]), int(s_plot10[i]),
+              s_plot11[i]);
+      t.push_back(T1[i]);
+      s_vec.push_back(s_plot9[i]);
+      s_vec2.push_back(s_plot3[i] + s_plot6[i]);
+      s_vec3.push_back(s_plot4[i]);
+      s_vec5.push_back(s_plot[i]);
     }
-    delete loopthread;
+    fclose(fp2);
+  }
+
+  startFlag = false;
+  if (locate_mode == false) {
+    loopthread->join(); //  分离线程
+  }
+  delete loopthread;
 
-    return 0;
+  return 0;
 }

+ 1 - 0
src/preprocess.cpp

@@ -157,6 +157,7 @@ void Preprocess::velodyne_handler(const sensor_msgs::PointCloud2::ConstPtr &msg)
   pl_full.clear();
 
   pcl::PointCloud<velodyne_ros::Point> pl_orig;
+
   pcl::fromROSMsg(*msg, pl_orig);
   int plsize = pl_orig.points.size();
   pl_surf.reserve(plsize);

+ 1 - 1
src/scancontext/Scancontext.cpp

@@ -401,7 +401,7 @@ std::pair<int, float> SCManager::detectLoopClosureID ( void )
         loop_id = nn_idx; 
     
         // std::cout.precision(3); 
-        std::cout << "[Loop found] Nearest distance: " << min_dist << ", between " << polarcontexts_.size()-1 << " and " << nn_idx  << std::endl;
+        //std::cout << "[Loop found] Nearest distance: " << min_dist << ", between " << polarcontexts_.size()-1 << " and " << nn_idx  << std::endl;
         // cout << "[Loop found] yaw diff: " << nn_align * PC_UNIT_SECTORANGLE << " deg." << endl;
     }
     /*else