1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455 |
- #include <omp.h>
- #include <mutex>
- #include <math.h>
- #include <thread>
- #include <fstream>
- #include <csignal>
- #include <unistd.h>
- #include <Python.h>
- #include <so3_math.h>
- #include <ros/ros.h>
- #include <Eigen/Core>
- #include "IMU_Processing.hpp"
- #include <nav_msgs/Odometry.h>
- #include <nav_msgs/Path.h>
- #include <visualization_msgs/Marker.h>
- #include <pcl_conversions/pcl_conversions.h>
- #include <pcl/point_cloud.h>
- #include <pcl/point_types.h>
- #include <pcl/filters/voxel_grid.h>
- #include <pcl/io/pcd_io.h>
- #include <sensor_msgs/PointCloud2.h>
- #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>
- #include <std_msgs/Header.h>
- #include <std_msgs/Float64MultiArray.h>
- #include <sensor_msgs/Imu.h>
- #include <sensor_msgs/PointCloud2.h>
- #include <sensor_msgs/NavSatFix.h>
- #include <nav_msgs/Odometry.h>
- #include <nav_msgs/Path.h>
- #include <visualization_msgs/Marker.h>
- #include <visualization_msgs/MarkerArray.h>
- #include <pcl/search/impl/search.hpp>
- #include <pcl/range_image/range_image.h>
- #include <pcl/kdtree/kdtree_flann.h>
- #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>
- #include <pcl_conversions/pcl_conversions.h>
- #include "scancontext/Scancontext.h"
- // gstam
- #include <gtsam/geometry/Rot3.h>
- #include <gtsam/geometry/Pose3.h>
- #include <gtsam/slam/PriorFactor.h>
- #include <gtsam/slam/BetweenFactor.h>
- #include <gtsam/navigation/GPSFactor.h>
- #include <gtsam/navigation/ImuFactor.h>
- #include <gtsam/navigation/CombinedImuFactor.h>
- #include <gtsam/nonlinear/NonlinearFactorGraph.h>
- #include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h>
- #include <gtsam/nonlinear/Marginals.h>
- #include <gtsam/nonlinear/Values.h>
- #include <gtsam/inference/Symbol.h>
- #include <gtsam/nonlinear/ISAM2.h>
- #include "keyFramesManager.h"
- /*
- // gnss
- #include "GNSS_Processing.hpp"
- #include "sensor_msgs/NavSatFix.h"
- */
- // save map
- #include "fast_lio_sam/save_map.h"
- #include "fast_lio_sam/save_pose.h"
- // save data in kitti format
- #include <sstream>
- #include <fstream>
- #include <iomanip>
- // using namespace gtsam;
- #define INIT_TIME (0.1)
- #define LASER_POINT_COV (0.001)
- #define MAXN (720000)
- #define PUBFRAME_PERIOD (20)
- /*** Time Log Variables ***/
- double kdtree_incremental_time = 0.0, kdtree_search_time = 0.0, kdtree_delete_time = 0.0;
- double T1[MAXN], s_plot[MAXN], s_plot2[MAXN], s_plot3[MAXN], s_plot4[MAXN], s_plot5[MAXN], s_plot6[MAXN], s_plot7[MAXN], s_plot8[MAXN], s_plot9[MAXN], s_plot10[MAXN], s_plot11[MAXN];
- double match_time = 0, solve_time = 0, solve_const_H_time = 0;
- int kdtree_size_st = 0, kdtree_size_end = 0, add_point_size = 0, kdtree_delete_counter = 0;
- bool runtime_pos_log = false, pcd_save_en = false, time_sync_en = false, extrinsic_est_en = true, path_en = true;
- bool locate_mode=false;
- /**************************/
- float res_last[100000] = {0.0}; //残差,点到面距离平方和
- float DET_RANGE = 300.0f;
- const float MOV_THRESHOLD = 1.5f;
- mutex mtx_buffer;
- condition_variable sig_buffer;
- string root_dir = ROOT_DIR;
- string map_file_path, lid_topic, imu_topic;
- double res_mean_last = 0.05, total_residual = 0.0;
- double last_timestamp_lidar = 0, last_timestamp_imu = -1.0;
- double gyr_cov = 0.1, acc_cov = 0.1, b_gyr_cov = 0.0001, b_acc_cov = 0.0001;
- double filter_size_corner_min = 0, filter_size_surf_min = 0, filter_size_map_min = 0, fov_deg = 0;
- double cube_len = 0, HALF_FOV_COS = 0, FOV_DEG = 0, total_distance = 0, lidar_end_time = 0, first_lidar_time = 0.0;
- int effct_feat_num = 0, time_log_counter = 0, scan_count = 0, publish_count = 0;
- int iterCount = 0, feats_down_size = 0, NUM_MAX_ITERATIONS = 0, laserCloudValidNum = 0, pcd_save_interval = -1, pcd_index = 0;
- bool point_selected_surf[100000] = {0}; // 是否为平面特征点
- bool lidar_pushed, flg_first_scan = true, flg_exit = false, flg_EKF_inited;
- bool scan_pub_en = false, dense_pub_en = false, scan_body_pub_en = false;
- vector<vector<int>> pointSearchInd_surf;
- vector<BoxPointType> cub_needrm; // ikd-tree中,地图需要移除的包围盒序列
- vector<PointVector> Nearest_Points;
- vector<double> extrinT(3, 0.0);
- vector<double> extrinR(9, 0.0);
- deque<double> time_buffer; // 记录lidar时间
- deque<PointCloudXYZI::Ptr> lidar_buffer; //记录特征提取或间隔采样后的lidar(特征)数据
- deque<sensor_msgs::Imu::ConstPtr> imu_buffer;
- PointCloudXYZI::Ptr featsFromMap(new PointCloudXYZI());
- PointCloudXYZI::Ptr feats_undistort(new PointCloudXYZI());
- PointCloudXYZI::Ptr feats_down_body(new PointCloudXYZI()); //畸变纠正后降采样的单帧点云,lidar系
- PointCloudXYZI::Ptr feats_down_world(new PointCloudXYZI()); //畸变纠正后降采样的单帧点云,w系
- PointCloudXYZI::Ptr normvec(new PointCloudXYZI(100000, 1)); //特征点在地图中对应点的,局部平面参数,w系
- PointCloudXYZI::Ptr laserCloudOri(new PointCloudXYZI(100000, 1));
- PointCloudXYZI::Ptr corr_normvect(new PointCloudXYZI(100000, 1)); //对应点法相量?
- PointCloudXYZI::Ptr _featsArray; // ikd-tree中,map需要移除的点云
- pcl::VoxelGrid<PointType> downSizeFilterSurf; //单帧内降采样使用voxel grid
- pcl::VoxelGrid<PointType> downSizeFilterMap; //未使用
- KD_TREE ikdtree;
- V3F XAxisPoint_body(LIDAR_SP_LEN, 0.0, 0.0);
- V3F XAxisPoint_world(LIDAR_SP_LEN, 0.0, 0.0);
- V3D euler_cur;
- V3D position_last(Zero3d);
- 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;
- nav_msgs::Odometry odomAftMapped;
- geometry_msgs::Quaternion geoQuat;
- geometry_msgs::PoseStamped msg_body_pose;
- shared_ptr<Preprocess> p_pre(new Preprocess());
- shared_ptr<ImuProcess> p_imu(new ImuProcess());
- /*back end*/
- vector<pcl::PointCloud<PointType>::Ptr> cornerCloudKeyFrames; // 历史所有关键帧的角点集合(降采样)
- vector<pcl::PointCloud<PointType>::Ptr> surfCloudKeyFrames; // 历史所有关键帧的平面点集合(降采样)
- pcl::PointCloud<PointType>::Ptr cloudKeyPoses3D(new pcl::PointCloud<PointType>()); // 历史关键帧位姿(位置)
- pcl::PointCloud<PointTypePose>::Ptr cloudKeyPoses6D(new pcl::PointCloud<PointTypePose>()); // 历史关键帧位姿
- pcl::PointCloud<PointType>::Ptr copy_cloudKeyPoses3D(new pcl::PointCloud<PointType>());
- pcl::PointCloud<PointTypePose>::Ptr copy_cloudKeyPoses6D(new pcl::PointCloud<PointTypePose>());
- pcl::PointCloud<PointTypePose>::Ptr fastlio_unoptimized_cloudKeyPoses6D(new pcl::PointCloud<PointTypePose>()); // 存储fastlio 未优化的位姿
- // voxel filter paprams
- float odometrySurfLeafSize;
- float mappingCornerLeafSize;
- float mappingSurfLeafSize;
- float z_tollerance;
- float rotation_tollerance;
- // CPU Params
- int numberOfCores = 4;
- double mappingProcessInterval;
- /*loop clousre*/
- bool startFlag = true;
- bool loopClosureEnableFlag;
- float loopClosureFrequency; // 回环检测频率
- int surroundingKeyframeSize;
- float historyKeyframeSearchRadius; // 回环检测 radius kdtree搜索半径
- float historyKeyframeSearchTimeDiff; // 帧间时间阈值
- int historyKeyframeSearchNum; // 回环时多少个keyframe拼成submap
- float historyKeyframeFitnessScore; // icp 匹配阈值
- bool potentialLoopFlag = false;
- ros::Publisher pubHistoryKeyFrames; // 发布 loop history keyframe submap
- ros::Publisher pubIcpKeyFrames;
- ros::Publisher pubRecentKeyFrames;
- ros::Publisher pubRecentKeyFrame;
- ros::Publisher pubCloudRegisteredRaw;
- ros::Publisher pubLoopConstraintEdge;
- bool aLoopIsClosed = false;
- map<int, int> loopIndexContainer; // from new to old
- vector<pair<int, int>> loopIndexQueue;
- vector<gtsam::Pose3> loopPoseQueue;
- vector<gtsam::noiseModel::Diagonal::shared_ptr> loopNoiseQueue;
- deque<std_msgs::Float64MultiArray> loopInfoVec;
- nav_msgs::Path globalPath;
- // 局部关键帧构建的map点云,对应kdtree,用于scan-to-map找相邻点
- pcl::KdTreeFLANN<PointType>::Ptr kdtreeCornerFromMap(new pcl::KdTreeFLANN<PointType>());
- pcl::KdTreeFLANN<PointType>::Ptr kdtreeSurfFromMap(new pcl::KdTreeFLANN<PointType>());
- pcl::KdTreeFLANN<PointType>::Ptr kdtreeSurroundingKeyPoses(new pcl::KdTreeFLANN<PointType>());
- pcl::KdTreeFLANN<PointType>::Ptr kdtreeHistoryKeyPoses(new pcl::KdTreeFLANN<PointType>());
- // 降采样
- pcl::VoxelGrid<PointType> downSizeFilterCorner;
- // pcl::VoxelGrid<PointType> downSizeFilterSurf;
- pcl::VoxelGrid<PointType> downSizeFilterICP;
- pcl::VoxelGrid<PointType> downSizeFilterSurroundingKeyPoses; // for surrounding key poses of scan-to-map optimization
- float transformTobeMapped[6]; // 当前帧的位姿(world系下)
- std::mutex mtx;
- std::mutex mtxLoopInfo;
- // Surrounding map
- float surroundingkeyframeAddingDistThreshold; // 判断是否为关键帧的距离阈值
- float surroundingkeyframeAddingAngleThreshold; // 判断是否为关键帧的角度阈值
- float surroundingKeyframeDensity;
- float surroundingKeyframeSearchRadius;
- // gtsam
- gtsam::NonlinearFactorGraph gtSAMgraph;
- gtsam::Values initialEstimate;
- gtsam::Values optimizedEstimate;
- gtsam::ISAM2 *isam;
- gtsam::Values isamCurrentEstimate;
- Eigen::MatrixXd poseCovariance;
- ros::Publisher pubLaserCloudSurround;
- ros::Publisher pubOptimizedGlobalMap ; // 发布最后优化的地图
- bool recontructKdTree = false;
- int updateKdtreeCount = 0 ; // 每100次更新一次
- bool visulize_IkdtreeMap = false; // visual iktree submap
- // global map visualization radius
- float globalMapVisualizationSearchRadius;
- float globalMapVisualizationPoseDensity;
- float globalMapVisualizationLeafSize;
- bool savePCD; // 是否保存地图
- string savePCDDirectory; // 保存路径
- bool ndt_loop=false;
- /*
- * scancontext 回环检测
- */
- SCManager scManager;
- double scDistThres=0.2;
- double scMaximumRadius=80;
- /**
- * 更新里程计轨迹
- */
- void updatePath(const PointTypePose &pose_in)
- {
- string odometryFrame = "camera_init";
- geometry_msgs::PoseStamped pose_stamped;
- pose_stamped.header.stamp = ros::Time().fromSec(pose_in.time);
- pose_stamped.header.frame_id = odometryFrame;
- pose_stamped.pose.position.x = pose_in.x;
- pose_stamped.pose.position.y = pose_in.y;
- pose_stamped.pose.position.z = pose_in.z;
- tf::Quaternion q = tf::createQuaternionFromRPY(pose_in.roll, pose_in.pitch, pose_in.yaw);
- pose_stamped.pose.orientation.x = q.x();
- pose_stamped.pose.orientation.y = q.y();
- pose_stamped.pose.orientation.z = q.z();
- pose_stamped.pose.orientation.w = q.w();
- globalPath.poses.push_back(pose_stamped);
- }
- /**
- * 对点云cloudIn进行变换transformIn,返回结果点云, 修改liosam, 考虑到外参的表示
- */
- pcl::PointCloud<PointType>::Ptr transformPointCloud(pcl::PointCloud<PointType>::Ptr cloudIn, PointTypePose *transformIn)
- {
- pcl::PointCloud<PointType>::Ptr cloudOut(new pcl::PointCloud<PointType>());
- int cloudSize = cloudIn->size();
- cloudOut->resize(cloudSize);
-
- // 注意:lio_sam 中的姿态用的euler表示,而fastlio存的姿态角是旋转矢量。而 pcl::getTransformation是将euler_angle 转换到rotation_matrix 不合适,注释
- // Eigen::Affine3f transCur = pcl::getTransformation(transformIn->x, transformIn->y, transformIn->z, transformIn->roll, transformIn->pitch, transformIn->yaw);
- Eigen::Isometry3d T_b_lidar(state_point.offset_R_L_I ); // 获取 body2lidar 外参
- T_b_lidar.pretranslate(state_point.offset_T_L_I);
- Eigen::Affine3f T_w_b_ = pcl::getTransformation(transformIn->x, transformIn->y, transformIn->z, transformIn->roll, transformIn->pitch, transformIn->yaw);
- Eigen::Isometry3d T_w_b ; // world2body
- T_w_b.matrix() = T_w_b_.matrix().cast<double>();
- Eigen::Isometry3d T_w_lidar = T_w_b * T_b_lidar ; // T_w_lidar 转换矩阵
- Eigen::Isometry3d transCur = T_w_lidar;
- #pragma omp parallel for num_threads(numberOfCores)
- for (int i = 0; i < cloudSize; ++i)
- {
- const auto &pointFrom = cloudIn->points[i];
- cloudOut->points[i].x = transCur(0, 0) * pointFrom.x + transCur(0, 1) * pointFrom.y + transCur(0, 2) * pointFrom.z + transCur(0, 3);
- cloudOut->points[i].y = transCur(1, 0) * pointFrom.x + transCur(1, 1) * pointFrom.y + transCur(1, 2) * pointFrom.z + transCur(1, 3);
- cloudOut->points[i].z = transCur(2, 0) * pointFrom.x + transCur(2, 1) * pointFrom.y + transCur(2, 2) * pointFrom.z + transCur(2, 3);
- cloudOut->points[i].intensity = pointFrom.intensity;
- }
- return cloudOut;
- }
- /**
- * 位姿格式变换
- */
- gtsam::Pose3 pclPointTogtsamPose3(PointTypePose thisPoint)
- {
- return gtsam::Pose3(gtsam::Rot3::RzRyRx(double(thisPoint.roll), double(thisPoint.pitch), double(thisPoint.yaw)),
- gtsam::Point3(double(thisPoint.x), double(thisPoint.y), double(thisPoint.z)));
- }
- /**
- * 位姿格式变换
- */
- gtsam::Pose3 trans2gtsamPose(float transformIn[])
- {
- return gtsam::Pose3(gtsam::Rot3::RzRyRx(transformIn[0], transformIn[1], transformIn[2]),
- gtsam::Point3(transformIn[3], transformIn[4], transformIn[5]));
- }
- /**
- * Eigen格式的位姿变换
- */
- Eigen::Affine3f pclPointToAffine3f(PointTypePose thisPoint)
- {
- return pcl::getTransformation(thisPoint.x, thisPoint.y, thisPoint.z, thisPoint.roll, thisPoint.pitch, thisPoint.yaw);
- }
- /**
- * Eigen格式的位姿变换
- */
- Eigen::Affine3f trans2Affine3f(float transformIn[])
- {
- return pcl::getTransformation(transformIn[3], transformIn[4], transformIn[5], transformIn[0], transformIn[1], transformIn[2]);
- }
- /**
- * 位姿格式变换
- */
- PointTypePose trans2PointTypePose(float transformIn[])
- {
- PointTypePose thisPose6D;
- thisPose6D.x = transformIn[3];
- thisPose6D.y = transformIn[4];
- thisPose6D.z = transformIn[5];
- thisPose6D.roll = transformIn[0];
- thisPose6D.pitch = transformIn[1];
- thisPose6D.yaw = transformIn[2];
- return thisPose6D;
- }
- /**
- * 发布thisCloud,返回thisCloud对应msg格式
- */
- sensor_msgs::PointCloud2 publishCloud(ros::Publisher *thisPub, pcl::PointCloud<PointType>::Ptr thisCloud, ros::Time thisStamp, std::string thisFrame)
- {
- sensor_msgs::PointCloud2 tempCloud;
- pcl::toROSMsg(*thisCloud, tempCloud);
- tempCloud.header.stamp = thisStamp;
- tempCloud.header.frame_id = thisFrame;
- if (thisPub->getNumSubscribers() != 0)
- thisPub->publish(tempCloud);
- return tempCloud;
- }
- /**
- * 点到坐标系原点距离
- */
- float pointDistance(PointType p)
- {
- return sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
- }
- /**
- * 两点之间距离
- */
- 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));
- }
- // eulerAngle 2 Quaterniond
- Eigen::Quaterniond EulerToQuat(float roll_, float pitch_, float yaw_)
- {
- Eigen::Quaterniond q ; // 四元数 q 和 -q 是相等的
- Eigen::AngleAxisd roll(double(roll_), Eigen::Vector3d::UnitX());
- Eigen::AngleAxisd pitch(double(pitch_), Eigen::Vector3d::UnitY());
- Eigen::AngleAxisd yaw(double(yaw_), Eigen::Vector3d::UnitZ());
- q = yaw * pitch * roll ;
- q.normalize();
- return q ;
- }
- // 将更新的pose赋值到 transformTobeMapped
- void getCurPose(state_ikfom cur_state)
- {
- // 欧拉角是没有群的性质,所以从SO3还是一般的rotation matrix 转换过来的结果一样
- Eigen::Vector3d eulerAngle = cur_state.rot.matrix().eulerAngles(2,1,0); // yaw pitch roll 单位:弧度
- // V3D eulerAngle = SO3ToEuler(cur_state.rot)/57.3 ; // fastlio 自带 roll pitch yaw 单位: 度,旋转顺序 zyx
- // transformTobeMapped[0] = eulerAngle(0); // roll 使用 SO3ToEuler 方法时,顺序是 rpy
- // transformTobeMapped[1] = eulerAngle(1); // pitch
- // transformTobeMapped[2] = eulerAngle(2); // yaw
-
- transformTobeMapped[0] = eulerAngle(2); // roll 使用 eulerAngles(2,1,0) 方法时,顺序是 ypr
- transformTobeMapped[1] = eulerAngle(1); // pitch
- transformTobeMapped[2] = eulerAngle(0); // yaw
- transformTobeMapped[3] = cur_state.pos(0); // x
- transformTobeMapped[4] = cur_state.pos(1); // y
- transformTobeMapped[5] = cur_state.pos(2); // z
- }
- /**
- * rviz展示闭环边
- */
- void visualizeLoopClosure()
- {
- ros::Time timeLaserInfoStamp = ros::Time().fromSec(lidar_end_time); // 时间戳
- string odometryFrame = "camera_init";
- if (loopIndexContainer.empty())
- return;
- visualization_msgs::MarkerArray markerArray;
- // 闭环顶点
- visualization_msgs::Marker markerNode;
- markerNode.header.frame_id = odometryFrame;
- markerNode.header.stamp = timeLaserInfoStamp;
- markerNode.action = visualization_msgs::Marker::ADD;
- markerNode.type = visualization_msgs::Marker::SPHERE_LIST;
- markerNode.ns = "loop_nodes";
- markerNode.id = 0;
- markerNode.pose.orientation.w = 1;
- markerNode.scale.x = 0.3;
- markerNode.scale.y = 0.3;
- markerNode.scale.z = 0.3;
- markerNode.color.r = 0;
- markerNode.color.g = 0.8;
- markerNode.color.b = 1;
- markerNode.color.a = 1;
- // 闭环边
- visualization_msgs::Marker markerEdge;
- markerEdge.header.frame_id = odometryFrame;
- markerEdge.header.stamp = timeLaserInfoStamp;
- markerEdge.action = visualization_msgs::Marker::ADD;
- markerEdge.type = visualization_msgs::Marker::LINE_LIST;
- markerEdge.ns = "loop_edges";
- markerEdge.id = 1;
- markerEdge.pose.orientation.w = 1;
- markerEdge.scale.x = 0.1;
- markerEdge.color.r = 0.9;
- markerEdge.color.g = 0.9;
- markerEdge.color.b = 0;
- markerEdge.color.a = 1;
- // 遍历闭环
- for (auto it = loopIndexContainer.begin(); it != loopIndexContainer.end(); ++it)
- {
- int key_cur = it->first;
- int key_pre = it->second;
- geometry_msgs::Point p;
- p.x = copy_cloudKeyPoses6D->points[key_cur].x;
- p.y = copy_cloudKeyPoses6D->points[key_cur].y;
- p.z = copy_cloudKeyPoses6D->points[key_cur].z;
- markerNode.points.push_back(p);
- markerEdge.points.push_back(p);
- p.x = copy_cloudKeyPoses6D->points[key_pre].x;
- p.y = copy_cloudKeyPoses6D->points[key_pre].y;
- p.z = copy_cloudKeyPoses6D->points[key_pre].z;
- markerNode.points.push_back(p);
- markerEdge.points.push_back(p);
- }
- markerArray.markers.push_back(markerNode);
- markerArray.markers.push_back(markerEdge);
- pubLoopConstraintEdge.publish(markerArray);
- }
- /**
- * 计算当前帧与前一帧位姿变换,如果变化太小,不设为关键帧,反之设为关键帧
- */
- bool saveFrame()
- {
- if (cloudKeyPoses3D->points.empty())
- return true;
- // 前一帧位姿
- Eigen::Affine3f transStart = pclPointToAffine3f(cloudKeyPoses6D->back());
- // 当前帧位姿
- Eigen::Affine3f transFinal = trans2Affine3f(transformTobeMapped);
- // Eigen::Affine3f transFinal = pcl::getTransformation(transformTobeMapped[3], transformTobeMapped[4], transformTobeMapped[5],
- // transformTobeMapped[0], transformTobeMapped[1], transformTobeMapped[2]);
-
- // 位姿变换增量
- Eigen::Affine3f transBetween = transStart.inverse() * transFinal;
- float x, y, z, roll, pitch, yaw;
- pcl::getTranslationAndEulerAngles(transBetween, x, y, z, roll, pitch, yaw); // 获取上一帧 相对 当前帧的 位姿
- // 旋转和平移量都较小,当前帧不设为关键帧
- if (abs(roll) < surroundingkeyframeAddingAngleThreshold &&
- abs(pitch) < surroundingkeyframeAddingAngleThreshold &&
- abs(yaw) < surroundingkeyframeAddingAngleThreshold &&
- sqrt(x * x + y * y + z * z) < surroundingkeyframeAddingDistThreshold)
- return false;
- return true;
- }
- /**
- * 添加激光里程计因子
- */
- void addOdomFactor()
- {
- if (cloudKeyPoses3D->points.empty())
- {
- // 第一帧初始化先验因子
- gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances((gtsam::Vector(6) <<1e-12, 1e-12, 1e-12, 1e-12, 1e-12, 1e-12).finished()); // rad*rad, meter*meter // indoor 1e-12, 1e-12, 1e-12, 1e-12, 1e-12, 1e-12 // 1e-2, 1e-2, M_PI*M_PI, 1e8, 1e8, 1e8
- gtSAMgraph.add(gtsam::PriorFactor<gtsam::Pose3>(0, trans2gtsamPose(transformTobeMapped), priorNoise));
- // 变量节点设置初始值
- initialEstimate.insert(0, trans2gtsamPose(transformTobeMapped));
- }
- else
- {
- // 添加激光里程计因子
- gtsam::noiseModel::Diagonal::shared_ptr odometryNoise = gtsam::noiseModel::Diagonal::Variances((gtsam::Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished());
- gtsam::Pose3 poseFrom = pclPointTogtsamPose3(cloudKeyPoses6D->points.back()); /// pre
- gtsam::Pose3 poseTo = trans2gtsamPose(transformTobeMapped); // cur
- // 参数:前一帧id,当前帧id,前一帧与当前帧的位姿变换(作为观测值),噪声协方差
- gtSAMgraph.add(gtsam::BetweenFactor<gtsam::Pose3>(cloudKeyPoses3D->size() - 1, cloudKeyPoses3D->size(), poseFrom.between(poseTo), odometryNoise));
- // 变量节点设置初始值
- initialEstimate.insert(cloudKeyPoses3D->size(), poseTo);
- }
- }
- /**
- * 添加闭环因子
- */
- void addLoopFactor()
- {
- if (loopIndexQueue.empty())
- return;
- // 闭环队列
- for (int i = 0; i < (int)loopIndexQueue.size(); ++i)
- {
- // 闭环边对应两帧的索引
- int indexFrom = loopIndexQueue[i].first; // cur
- int indexTo = loopIndexQueue[i].second; // pre
- // 闭环边的位姿变换
- gtsam::Pose3 poseBetween = loopPoseQueue[i];
- gtsam::noiseModel::Diagonal::shared_ptr noiseBetween = loopNoiseQueue[i];
- gtSAMgraph.add(gtsam::BetweenFactor<gtsam::Pose3>(indexFrom, indexTo, poseBetween, noiseBetween));
- printf(" Add loop factor between %d -- %d\n",indexFrom,indexTo);
- }
- loopIndexQueue.clear();
- loopPoseQueue.clear();
- loopNoiseQueue.clear();
- aLoopIsClosed = true;
- }
- /**
- * 提取key索引的关键帧前后相邻若干帧的关键帧特征点集合,降采样
- */
- void loopFindNearKeyframes(pcl::PointCloud<PointType>::Ptr &nearKeyframes, const int &key, const int &searchNum)
- {
- // 提取key索引的关键帧前后相邻若干帧的关键帧特征点集合
- nearKeyframes->clear();
- int cloudSize = copy_cloudKeyPoses6D->size();
- auto surfcloud_keyframes_size = surfCloudKeyFrames.size() ;
- for (int i = -searchNum; i <= searchNum; ++i)
- {
- int keyNear = key + i;
- if (keyNear < 0 || keyNear >= cloudSize)
- continue;
- if (keyNear < 0 || keyNear >= surfcloud_keyframes_size)
- continue;
- // *nearKeyframes += *transformPointCloud(cornerCloudKeyFrames[keyNear], ©_cloudKeyPoses6D->points[keyNear]);
- // 注意:cloudKeyPoses6D 存储的是 T_w_b , 而点云是lidar系下的,构建icp的submap时,需要通过外参数T_b_lidar 转换 , 参考pointBodyToWorld 的转换
- *nearKeyframes += *transformPointCloud(surfCloudKeyFrames[keyNear], ©_cloudKeyPoses6D->points[keyNear]); // fast-lio 没有进行特征提取,默认点云就是surf
- }
- if (nearKeyframes->empty())
- return;
- // 降采样
- pcl::PointCloud<PointType>::Ptr cloud_temp(new pcl::PointCloud<PointType>());
- downSizeFilterICP.setInputCloud(nearKeyframes);
- downSizeFilterICP.filter(*cloud_temp);
- *nearKeyframes = *cloud_temp;
- }
- void performLoopClosure() {
- ros::Time timeLaserInfoStamp = ros::Time().fromSec(lidar_end_time); // 时间戳
- string odometryFrame = "camera_init";
- if (cloudKeyPoses3D->points.empty() == true) {
- return;
- }
- mtx.lock();
- *copy_cloudKeyPoses3D = *cloudKeyPoses3D;
- *copy_cloudKeyPoses6D = *cloudKeyPoses6D;
- mtx.unlock();
- // 当前关键帧索引,候选闭环匹配帧索引
- static int LastKeyFrameSize=0;//;
- if(LastKeyFrameSize>=surfCloudKeyFrames.size()) //没有更新的keyframe 无需检测
- return ;
- int loopKeyCur;
- int loopKeyPre;
- // 在历史关键帧中查找与当前关键帧距离最近的关键帧集合,选择时间相隔较远的一帧作为候选闭环帧
- /*if (detectLoopClosureDistance(&loopKeyCur, &loopKeyPre) == false)
- {
- return;
- }*/
- if( int(cloudKeyPoses3D->size()) < scManager.NUM_EXCLUDE_RECENT) // do not try too early
- return;
- auto detectResult = scManager.detectLoopClosureID(); // first: nn index, second: yaw diff
- LastKeyFrameSize=surfCloudKeyFrames.size();
- int SCclosestHistoryFrameID = detectResult.first;
- if( SCclosestHistoryFrameID != -1 ) {
- loopKeyPre = SCclosestHistoryFrameID;
- loopKeyCur = cloudKeyPoses3D->size() - 1; // because cpp starts 0 and ends n-1
- //cout << "Loop detected! - between " << loopKeyPre << " and " << loopKeyCur << "" << endl;
- }else{
- return;
- }
- // 提取
- pcl::PointCloud<PointType>::Ptr cureKeyframeCloud(new pcl::PointCloud<PointType>()); // cue keyframe
- pcl::PointCloud<PointType>::Ptr prevKeyframeCloud(new pcl::PointCloud<PointType>()); // history keyframe submap
- {
- // 提取当前关键帧特征点集合,降采样
- loopFindNearKeyframes(cureKeyframeCloud, loopKeyCur, 0); // 将cur keyframe 转换到world系下
- // 提取闭环匹配关键帧前后相邻若干帧的关键帧特征点集合,降采样
- loopFindNearKeyframes(prevKeyframeCloud, loopKeyPre,
- historyKeyframeSearchNum); // 选取historyKeyframeSearchNum个keyframe拼成submap
- // 如果特征点较少,返回
- // if (cureKeyframeCloud->size() < 300 || prevKeyframeCloud->size() < 1000)
- // return;
- // 发布闭环匹配关键帧局部map
- if (pubHistoryKeyFrames.getNumSubscribers() != 0)
- 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);
- icp.setTransformationEpsilon(1e-6);
- icp.setEuclideanFitnessEpsilon(1e-6);
- icp.setRANSACIterations(0);
- // scan-to-map,调用icp匹配
- icp.setInputSource(cureKeyframeCloud);
- icp.setInputTarget(prevKeyframeCloud);
- pcl::PointCloud<PointType>::Ptr unused_result(new pcl::PointCloud<PointType>());
- icp.align(*unused_result);
- 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;
- }
- 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, correctionLidarFrame);
- publishCloud(&pubIcpKeyFrames, closed_cloud, timeLaserInfoStamp, odometryFrame);
- }
- // 闭环优化得到的当前关键帧与闭环关键帧之间的位姿变换
- // 闭环优化前当前帧位姿
- Eigen::Affine3f tWrong = pclPointToAffine3f(copy_cloudKeyPoses6D->points[loopKeyCur]);
- // 闭环优化后当前帧位姿
- Eigen::Affine3f tCorrect = correctionLidarFrame * tWrong;
- 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);
- Vector6 << noiseScore, noiseScore, noiseScore, noiseScore, noiseScore, noiseScore;
- gtsam::noiseModel::Diagonal::shared_ptr constraintNoise = gtsam::noiseModel::Diagonal::Variances(Vector6);
- std::cout << "loopNoiseQueue = " << noiseScore << std::endl;
- // 添加闭环因子需要的数据
- mtx.lock();
- loopIndexQueue.push_back(make_pair(loopKeyCur, loopKeyPre));
- loopPoseQueue.push_back(poseFrom.between(poseTo));
- loopNoiseQueue.push_back(constraintNoise);
- mtx.unlock();
- loopIndexContainer[loopKeyCur] = loopKeyPre; // 使用hash map 存储回环对
- }
- void saveKeyFramesAndFactor()
- {
- // 计算当前帧与前一帧位姿变换,如果变化太小,不设为关键帧,反之设为关键帧
- if (saveFrame() == false)
- return;
- // 激光里程计因子(from fast-lio), 输入的是frame_relative pose 帧间位姿(body 系下)
- addOdomFactor();
- scManager.makeAndSaveScancontextAndKeys(*feats_undistort);
- performLoopClosure(); //闭环检测
- visualizeLoopClosure();//展示闭环边
- // 闭环因子 (rs-loop-detect) 基于欧氏距离的检测
- addLoopFactor();
- // 执行优化
- isam->update(gtSAMgraph, initialEstimate);
- isam->update();
- if (aLoopIsClosed == true) // 有回环因子,多update几次
- {
- isam->update();
- isam->update();
- isam->update();
- isam->update();
- isam->update();
- printf(" isam update \n");
- }
- // update之后要清空一下保存的因子图,注:历史数据不会清掉,ISAM保存起来了
- gtSAMgraph.resize(0);
- initialEstimate.clear();
- PointType thisPose3D;
- PointTypePose thisPose6D;
- gtsam::Pose3 latestEstimate;
- // 优化结果
- isamCurrentEstimate = isam->calculateBestEstimate();
- // 当前帧位姿结果
- latestEstimate = isamCurrentEstimate.at<gtsam::Pose3>(isamCurrentEstimate.size() - 1);
- // cloudKeyPoses3D加入当前帧位置
- thisPose3D.x = latestEstimate.translation().x();
- thisPose3D.y = latestEstimate.translation().y();
- thisPose3D.z = latestEstimate.translation().z();
- // 索引
- thisPose3D.intensity = cloudKeyPoses3D->size(); // 使用intensity作为该帧点云的index
- cloudKeyPoses3D->push_back(thisPose3D); // 新关键帧帧放入队列中
- // cloudKeyPoses6D加入当前帧位姿
- thisPose6D.x = thisPose3D.x;
- thisPose6D.y = thisPose3D.y;
- thisPose6D.z = thisPose3D.z;
- thisPose6D.intensity = thisPose3D.intensity;
- thisPose6D.roll = latestEstimate.rotation().roll();
- thisPose6D.pitch = latestEstimate.rotation().pitch();
- thisPose6D.yaw = latestEstimate.rotation().yaw();
- thisPose6D.time = lidar_end_time;
- cloudKeyPoses6D->push_back(thisPose6D);
- // 位姿协方差
- poseCovariance = isam->marginalCovariance(isamCurrentEstimate.size() - 1);
- // ESKF状态和方差 更新
- state_ikfom state_updated = ikfom_.get_x(); // 获取cur_pose (还没修正)
- Eigen::Vector3d pos(latestEstimate.translation().x(), latestEstimate.translation().y(), latestEstimate.translation().z());
- Eigen::Quaterniond q = EulerToQuat(latestEstimate.rotation().roll(), latestEstimate.rotation().pitch(), latestEstimate.rotation().yaw());
- // 更新状态量
- state_updated.pos = pos;
- state_updated.rot = q;
- state_point = state_updated; // 对state_point进行更新,state_point可视化用到
- // if(aLoopIsClosed == true )
- ikfom_.change_x(state_updated); // 对cur_pose 进行isam2优化后的修正
- // TODO: P的修正有待考察,按照yanliangwang的做法,修改了p,会跑飞
- // esekfom::esekf<state_ikfom, 12, input_ikfom>::cov P_updated = kf.get_P(); // 获取当前的状态估计的协方差矩阵
- // P_updated.setIdentity();
- // P_updated(6, 6) = P_updated(7, 7) = P_updated(8, 8) = 0.00001;
- // P_updated(9, 9) = P_updated(10, 10) = P_updated(11, 11) = 0.00001;
- // P_updated(15, 15) = P_updated(16, 16) = P_updated(17, 17) = 0.0001;
- // P_updated(18, 18) = P_updated(19, 19) = P_updated(20, 20) = 0.001;
- // P_updated(21, 21) = P_updated(22, 22) = 0.00001;
- // kf.change_P(P_updated);
- // 当前帧激光角点、平面点,降采样集合
- // pcl::PointCloud<PointType>::Ptr thisCornerKeyFrame(new pcl::PointCloud<PointType>());
- pcl::PointCloud<PointType>::Ptr thisSurfKeyFrame(new pcl::PointCloud<PointType>());
- // pcl::copyPointCloud(*feats_undistort, *thisCornerKeyFrame);
- pcl::copyPointCloud(*feats_undistort, *thisSurfKeyFrame); // 存储关键帧,没有降采样的点云
- // 保存特征点降采样集合
- // cornerCloudKeyFrames.push_back(thisCornerKeyFrame);
- surfCloudKeyFrames.push_back(thisSurfKeyFrame);
- //sc关键帧保存降采样的点云
- /*pcl::PointCloud<PointType>::Ptr cloud_temp(new pcl::PointCloud<PointType>());
- downSizeFilterICP.setInputCloud(thisSurfKeyFrame);
- downSizeFilterICP.filter(*cloud_temp);*/
- updatePath(thisPose6D); // 可视化update后的path
- }
- void recontructIKdTree(){
- if(recontructKdTree && updateKdtreeCount > 0){
- /*** if path is too large, the rvis will crash ***/
- pcl::KdTreeFLANN<PointType>::Ptr kdtreeGlobalMapPoses(new pcl::KdTreeFLANN<PointType>());
- pcl::PointCloud<PointType>::Ptr subMapKeyPoses(new pcl::PointCloud<PointType>());
- pcl::PointCloud<PointType>::Ptr subMapKeyPosesDS(new pcl::PointCloud<PointType>());
- pcl::PointCloud<PointType>::Ptr subMapKeyFrames(new pcl::PointCloud<PointType>());
- pcl::PointCloud<PointType>::Ptr subMapKeyFramesDS(new pcl::PointCloud<PointType>());
- // kdtree查找最近一帧关键帧相邻的关键帧集合
- std::vector<int> pointSearchIndGlobalMap;
- std::vector<float> pointSearchSqDisGlobalMap;
- mtx.lock();
- kdtreeGlobalMapPoses->setInputCloud(cloudKeyPoses3D);
- kdtreeGlobalMapPoses->radiusSearch(cloudKeyPoses3D->back(), globalMapVisualizationSearchRadius, pointSearchIndGlobalMap, pointSearchSqDisGlobalMap, 0);
- mtx.unlock();
- for (int i = 0; i < (int)pointSearchIndGlobalMap.size(); ++i)
- subMapKeyPoses->push_back(cloudKeyPoses3D->points[pointSearchIndGlobalMap[i]]); // subMap的pose集合
- // 降采样
- pcl::VoxelGrid<PointType> downSizeFilterSubMapKeyPoses;
- downSizeFilterSubMapKeyPoses.setLeafSize(globalMapVisualizationPoseDensity, globalMapVisualizationPoseDensity, globalMapVisualizationPoseDensity); // for global map visualization
- downSizeFilterSubMapKeyPoses.setInputCloud(subMapKeyPoses);
- downSizeFilterSubMapKeyPoses.filter(*subMapKeyPosesDS); // subMap poses downsample
- // 提取局部相邻关键帧对应的特征点云
- for (int i = 0; i < (int)subMapKeyPosesDS->size(); ++i)
- {
- // 距离过大
- if (pointDistance(subMapKeyPosesDS->points[i], cloudKeyPoses3D->back()) > globalMapVisualizationSearchRadius)
- continue;
- int thisKeyInd = (int)subMapKeyPosesDS->points[i].intensity;
- // *globalMapKeyFrames += *transformPointCloud(cornerCloudKeyFrames[thisKeyInd], &cloudKeyPoses6D->points[thisKeyInd]);
- *subMapKeyFrames += *transformPointCloud(surfCloudKeyFrames[thisKeyInd], &cloudKeyPoses6D->points[thisKeyInd]); // fast_lio only use surfCloud
- }
- // 降采样,发布
- pcl::VoxelGrid<PointType> downSizeFilterGlobalMapKeyFrames; // for global map visualization
- downSizeFilterGlobalMapKeyFrames.setLeafSize(globalMapVisualizationLeafSize, globalMapVisualizationLeafSize, globalMapVisualizationLeafSize); // for global map visualization
- downSizeFilterGlobalMapKeyFrames.setInputCloud(subMapKeyFrames);
- downSizeFilterGlobalMapKeyFrames.filter(*subMapKeyFramesDS);
- std::cout << "subMapKeyFramesDS sizes = " << subMapKeyFramesDS->points.size() << std::endl;
-
- ikdtree.reconstruct(subMapKeyFramesDS->points);
- updateKdtreeCount = 0;
- ROS_INFO("Reconstructed ikdtree ");
- int featsFromMapNum = ikdtree.validnum();
- kdtree_size_st = ikdtree.size();
- std::cout << "featsFromMapNum = " << featsFromMapNum << "\t" << " kdtree_size_st = " << kdtree_size_st << std::endl;
- }
- updateKdtreeCount ++ ;
- }
- /**
- * 更新因子图中所有变量节点的位姿,也就是所有历史关键帧的位姿,更新里程计轨迹
- */
- void correctPoses()
- {
- if (cloudKeyPoses3D->points.empty())
- return;
- if (aLoopIsClosed == true)
- {
- // 清空里程计轨迹
- globalPath.poses.clear();
- // 更新因子图中所有变量节点的位姿,也就是所有历史关键帧的位姿
- int numPoses = isamCurrentEstimate.size();
- for (int i = 0; i < numPoses; ++i)
- {
- cloudKeyPoses3D->points[i].x = isamCurrentEstimate.at<gtsam::Pose3>(i).translation().x();
- cloudKeyPoses3D->points[i].y = isamCurrentEstimate.at<gtsam::Pose3>(i).translation().y();
- cloudKeyPoses3D->points[i].z = isamCurrentEstimate.at<gtsam::Pose3>(i).translation().z();
- cloudKeyPoses6D->points[i].x = cloudKeyPoses3D->points[i].x;
- cloudKeyPoses6D->points[i].y = cloudKeyPoses3D->points[i].y;
- cloudKeyPoses6D->points[i].z = cloudKeyPoses3D->points[i].z;
- cloudKeyPoses6D->points[i].roll = isamCurrentEstimate.at<gtsam::Pose3>(i).rotation().roll();
- cloudKeyPoses6D->points[i].pitch = isamCurrentEstimate.at<gtsam::Pose3>(i).rotation().pitch();
- cloudKeyPoses6D->points[i].yaw = isamCurrentEstimate.at<gtsam::Pose3>(i).rotation().yaw();
- // 更新里程计轨迹
- updatePath(cloudKeyPoses6D->points[i]);
- }
- // 清空局部map, reconstruct ikdtree submap
- recontructIKdTree();
- ROS_INFO("ISMA2 Update");
- aLoopIsClosed = false;
- }
- }
- //回环检测三大要素
- // 1.设置最小时间差,太近没必要
- // 2.控制回环的频率,避免频繁检测,每检测一次,就做一次等待
- // 3.根据当前最小距离重新计算等待时间
- bool detectLoopClosureDistance(int *latestID, int *closestID)
- {
- // 当前关键帧帧
- int loopKeyCur = copy_cloudKeyPoses3D->size() - 1; // 当前关键帧索引
- int loopKeyPre = -1;
- // 当前帧已经添加过闭环对应关系,不再继续添加
- auto it = loopIndexContainer.find(loopKeyCur);
- if (it != loopIndexContainer.end())
- return false;
- // 在历史关键帧中查找与当前关键帧距离最近的关键帧集合
- std::vector<int> pointSearchIndLoop; // 候选关键帧索引
- std::vector<float> pointSearchSqDisLoop; // 候选关键帧距离
- kdtreeHistoryKeyPoses->setInputCloud(copy_cloudKeyPoses3D); // 历史帧构建kdtree
- kdtreeHistoryKeyPoses->radiusSearch(copy_cloudKeyPoses3D->back(), historyKeyframeSearchRadius, pointSearchIndLoop, pointSearchSqDisLoop, 0);
- // 在候选关键帧集合中,找到与当前帧时间相隔较远的帧,设为候选匹配帧
- for (int i = 0; i < (int)pointSearchIndLoop.size(); ++i)
- {
- int id = pointSearchIndLoop[i];
- if (abs(copy_cloudKeyPoses6D->points[id].time - lidar_end_time) > historyKeyframeSearchTimeDiff)
- {
- loopKeyPre = id;
- break;
- }
- }
- if (loopKeyPre == -1 || loopKeyCur == loopKeyPre)
- return false;
- *latestID = loopKeyCur;
- *closestID = loopKeyPre;
- ROS_INFO("Find loop clousre frame ");
- return true;
- }
- //回环检测线程
- void loopClosureThread()
- {
- /*if (loopClosureEnableFlag == false)
- {
- std::cout << "loopClosureEnableFlag == false " << endl;
- return;
- }
- ros::Rate rate(loopClosureFrequency); // 回环频率
- while (ros::ok() && startFlag)
- {
- rate.sleep();
- performLoopClosure(); // 回环检测
- visualizeLoopClosure(); // rviz展示闭环边
- }*/
- }
- void SigHandle(int sig)
- {
- flg_exit = true;
- ROS_WARN("catch sig %d", sig);
- sig_buffer.notify_all();
- }
- inline void dump_lio_state_to_log(FILE *fp)
- {
- V3D rot_ang(Log(state_point.rot.toRotationMatrix()));
- fprintf(fp, "%lf ", Measures.lidar_beg_time - first_lidar_time);
- fprintf(fp, "%lf %lf %lf ", rot_ang(0), rot_ang(1), rot_ang(2)); // Angle
- fprintf(fp, "%lf %lf %lf ", state_point.pos(0), state_point.pos(1), state_point.pos(2)); // Pos
- fprintf(fp, "%lf %lf %lf ", 0.0, 0.0, 0.0); // omega
- fprintf(fp, "%lf %lf %lf ", state_point.vel(0), state_point.vel(1), state_point.vel(2)); // Vel
- fprintf(fp, "%lf %lf %lf ", 0.0, 0.0, 0.0); // Acc
- fprintf(fp, "%lf %lf %lf ", state_point.bg(0), state_point.bg(1), state_point.bg(2)); // Bias_g
- fprintf(fp, "%lf %lf %lf ", state_point.ba(0), state_point.ba(1), state_point.ba(2)); // Bias_a
- fprintf(fp, "%lf %lf %lf ", state_point.grav[0], state_point.grav[1], state_point.grav[2]); // Bias_a
- fprintf(fp, "\r\n");
- fflush(fp);
- }
- void pointBodyToWorld_ikfom(PointType const *const pi, PointType *const po, state_ikfom &s)
- {
- V3D p_body(pi->x, pi->y, pi->z);
- V3D p_global(s.rot * (s.offset_R_L_I * p_body + s.offset_T_L_I) + s.pos);
- po->x = p_global(0);
- po->y = p_global(1);
- po->z = p_global(2);
- po->intensity = pi->intensity;
- }
- //按当前body(lidar)的状态,将局部点转换到世界系下
- void pointBodyToWorld(PointType const *const pi, PointType *const po)
- {
- V3D p_body(pi->x, pi->y, pi->z);
- // world <-- imu <-- lidar
- V3D p_global(state_point.rot * (state_point.offset_R_L_I * p_body + state_point.offset_T_L_I) + state_point.pos);
- po->x = p_global(0);
- po->y = p_global(1);
- po->z = p_global(2);
- po->intensity = pi->intensity;
- }
- template <typename T>
- void pointBodyToWorld(const Matrix<T, 3, 1> &pi, Matrix<T, 3, 1> &po)
- {
- V3D p_body(pi[0], pi[1], pi[2]);
- V3D p_global(state_point.rot * (state_point.offset_R_L_I * p_body + state_point.offset_T_L_I) + state_point.pos);
- po[0] = p_global(0);
- po[1] = p_global(1);
- po[2] = p_global(2);
- }
- void RGBpointBodyToWorld(PointType const *const pi, PointType *const po) // lidar2world
- {
- V3D p_body(pi->x, pi->y, pi->z);
- V3D p_global(state_point.rot * (state_point.offset_R_L_I * p_body + state_point.offset_T_L_I) + state_point.pos);
- po->x = p_global(0);
- po->y = p_global(1);
- po->z = p_global(2);
- po->intensity = pi->intensity;
- }
- void test_RGBpointBodyToWorld(PointType const *const pi, PointType *const po,Eigen::Vector3d pos, Eigen::Matrix3d rotation) // lidar2world
- {
- V3D p_body(pi->x, pi->y, pi->z);
- V3D p_global(rotation * (state_point.offset_R_L_I * p_body + state_point.offset_T_L_I) + pos);
- po->x = p_global(0);
- po->y = p_global(1);
- po->z = p_global(2);
- po->intensity = pi->intensity;
- }
- void RGBpointBodyLidarToIMU(PointType const *const pi, PointType *const po)
- {
- V3D p_body_lidar(pi->x, pi->y, pi->z);
- V3D p_body_imu(state_point.offset_R_L_I * p_body_lidar + state_point.offset_T_L_I);
- po->x = p_body_imu(0);
- po->y = p_body_imu(1);
- po->z = p_body_imu(2);
- po->intensity = pi->intensity;
- }
- void points_cache_collect()
- {
- PointVector points_history;
- ikdtree.acquire_removed_points(points_history);
- for (int i = 0; i < points_history.size(); i++)
- _featsArray->push_back(points_history[i]);
- }
- //根据lidar的FoV分割场景
- BoxPointType LocalMap_Points; // ikd-tree中,局部地图的包围盒角点
- bool Localmap_Initialized = false;
- void lasermap_fov_segment()
- {
- cub_needrm.clear(); // 清空需要移除的区域
- kdtree_delete_counter = 0;
- kdtree_delete_time = 0.0;
- pointBodyToWorld(XAxisPoint_body, XAxisPoint_world); // X轴分界点转换到w系下
- V3D pos_LiD = pos_lid; // global系lidar位置
- //初始化局部地图包围盒角点,以为w系下lidar位置为中心
- if (!Localmap_Initialized)
- {
- for (int i = 0; i < 3; i++)
- {
- LocalMap_Points.vertex_min[i] = pos_LiD(i) - cube_len / 2.0;
- LocalMap_Points.vertex_max[i] = pos_LiD(i) + cube_len / 2.0;
- }
- Localmap_Initialized = true;
- return;
- }
- float dist_to_map_edge[3][2]; //各个方向与局部地图边界的距离
- bool need_move = false;
- for (int i = 0; i < 3; i++)
- {
- dist_to_map_edge[i][0] = fabs(pos_LiD(i) - LocalMap_Points.vertex_min[i]);
- dist_to_map_edge[i][1] = fabs(pos_LiD(i) - LocalMap_Points.vertex_max[i]);
- //与某个方向上的边界距离太小,标记需要移除need_move
- if (dist_to_map_edge[i][0] <= MOV_THRESHOLD * DET_RANGE || dist_to_map_edge[i][1] <= MOV_THRESHOLD * DET_RANGE)
- need_move = true;
- }
- //不需要移除则直接返回
- if (!need_move)
- return;
- BoxPointType New_LocalMap_Points, tmp_boxpoints;
- New_LocalMap_Points = LocalMap_Points; // 新的局部地图角点
- float mov_dist = max((cube_len - 2.0 * MOV_THRESHOLD * DET_RANGE) * 0.5 * 0.9, double(DET_RANGE * (MOV_THRESHOLD - 1)));
- for (int i = 0; i < 3; i++)
- {
- tmp_boxpoints = LocalMap_Points;
- //与包围盒最小值角点距离
- if (dist_to_map_edge[i][0] <= MOV_THRESHOLD * DET_RANGE)
- {
- New_LocalMap_Points.vertex_max[i] -= mov_dist;
- New_LocalMap_Points.vertex_min[i] -= mov_dist;
- tmp_boxpoints.vertex_min[i] = LocalMap_Points.vertex_max[i] - mov_dist;
- cub_needrm.push_back(tmp_boxpoints); // 移除较远包围盒
- }
- else if (dist_to_map_edge[i][1] <= MOV_THRESHOLD * DET_RANGE)
- {
- New_LocalMap_Points.vertex_max[i] += mov_dist;
- New_LocalMap_Points.vertex_min[i] += mov_dist;
- tmp_boxpoints.vertex_max[i] = LocalMap_Points.vertex_min[i] + mov_dist;
- cub_needrm.push_back(tmp_boxpoints);
- }
- }
- LocalMap_Points = New_LocalMap_Points;
- points_cache_collect();
- double delete_begin = omp_get_wtime();
- if (cub_needrm.size() > 0)
- kdtree_delete_counter = ikdtree.Delete_Point_Boxes(cub_needrm);
- kdtree_delete_time = omp_get_wtime() - delete_begin;
- }
- void standard_pcl_cbk(const sensor_msgs::PointCloud2::ConstPtr &msg)
- {
- mtx_buffer.lock();
- scan_count++;
- double preprocess_start_time = omp_get_wtime();
- if (msg->header.stamp.toSec() < last_timestamp_lidar)
- {
- ROS_ERROR("lidar loop back, clear buffer");
- lidar_buffer.clear();
- }
- PointCloudXYZI::Ptr ptr(new PointCloudXYZI());
- p_pre->process(msg, ptr);
- lidar_buffer.push_back(ptr);
- time_buffer.push_back(msg->header.stamp.toSec());
- last_timestamp_lidar = msg->header.stamp.toSec();
- s_plot11[scan_count] = omp_get_wtime() - preprocess_start_time;
- mtx_buffer.unlock();
- sig_buffer.notify_all();
- }
- double timediff_lidar_wrt_imu = 0.0;
- bool timediff_set_flg = false; // 标记是否已经进行了时间补偿
- void livox_pcl_cbk(const livox_ros_driver::CustomMsg::ConstPtr &msg)
- {
- mtx_buffer.lock();
- double preprocess_start_time = omp_get_wtime();
- scan_count++;
- if (msg->header.stamp.toSec() < last_timestamp_lidar)
- {
- ROS_ERROR("lidar loop back, clear buffer");
- lidar_buffer.clear();
- }
- last_timestamp_lidar = msg->header.stamp.toSec();
- if (!time_sync_en && abs(last_timestamp_imu - last_timestamp_lidar) > 10.0 && !imu_buffer.empty() && !lidar_buffer.empty())
- {
- printf("IMU and LiDAR not Synced, IMU time: %lf, lidar header time: %lf \n", last_timestamp_imu, last_timestamp_lidar);
- }
- if (time_sync_en && !timediff_set_flg && abs(last_timestamp_lidar - last_timestamp_imu) > 1 && !imu_buffer.empty())
- {
- timediff_set_flg = true;
- timediff_lidar_wrt_imu = last_timestamp_lidar + 0.1 - last_timestamp_imu; //????
- printf("Self sync IMU and LiDAR, time diff is %.10lf \n", timediff_lidar_wrt_imu);
- }
- PointCloudXYZI::Ptr ptr(new PointCloudXYZI());
- // 特征提取或间隔采样
- p_pre->process(msg, ptr);
- lidar_buffer.push_back(ptr); //储存处理后的lidar特征
- time_buffer.push_back(last_timestamp_lidar);
- s_plot11[scan_count] = omp_get_wtime() - preprocess_start_time;
- mtx_buffer.unlock();
- sig_buffer.notify_all();
- }
- void imu_cbk(const sensor_msgs::Imu::ConstPtr &msg_in)
- {
- publish_count++;
- // cout<<"IMU got at: "<<msg_in->header.stamp.toSec()<<endl;
- sensor_msgs::Imu::Ptr msg(new sensor_msgs::Imu(*msg_in));
- // lidar 和 imu时间差过大,且开启 时间同步, 纠正当前输入imu的时间
- if (abs(timediff_lidar_wrt_imu) > 0.1 && time_sync_en)
- {
- // 对输入imu时间,纠正为 时间差 + 原始时间
- msg->header.stamp =
- ros::Time().fromSec(timediff_lidar_wrt_imu + msg_in->header.stamp.toSec());
- }
- double timestamp = msg->header.stamp.toSec();
- mtx_buffer.lock();
- if (timestamp < last_timestamp_imu)
- {
- ROS_WARN("imu loop back, clear buffer");
- imu_buffer.clear();
- }
- last_timestamp_imu = timestamp; // update imu time
- imu_buffer.push_back(msg);
- mtx_buffer.unlock();
- sig_buffer.notify_all();
- }
- double lidar_mean_scantime = 0.0;
- int scan_num = 0;
- bool sync_packages(MeasureGroup &meas)
- {
- if (lidar_buffer.empty() || imu_buffer.empty())
- {
- return false;
- }
- /*** push a lidar scan ***/
- if (!lidar_pushed)
- {
- meas.lidar = lidar_buffer.front(); // lidar指针指向最旧的lidar数据
- meas.lidar_beg_time = time_buffer.front(); //记录最早时间
- //更新结束时刻的时间
- if (meas.lidar->points.size() <= 1) // time too little 时间太短,点数不足
- {
- lidar_end_time = meas.lidar_beg_time + lidar_mean_scantime; // 记录lidar结束时间为 起始时间 + 单帧扫描时间
- ROS_WARN("Too few input point cloud!\n");
- }
- else if (meas.lidar->points.back().curvature / double(1000) < 0.5 * lidar_mean_scantime) //最后一个点的时间 小于 单帧扫描时间的一半
- {
- lidar_end_time = meas.lidar_beg_time + lidar_mean_scantime; // 记录lidar结束时间为 起始时间 + 单帧扫描时间
- }
- else
- {
- scan_num++;
- lidar_end_time = meas.lidar_beg_time + meas.lidar->points.back().curvature / double(1000); //结束时间设置为 起始时间 + 最后一个点的时间(相对)
- // 动态更新每帧lidar数据平均扫描时间
- lidar_mean_scantime += (meas.lidar->points.back().curvature / double(1000) - lidar_mean_scantime) / scan_num;
- }
- meas.lidar_end_time = lidar_end_time;
- lidar_pushed = true;
- }
- if (last_timestamp_imu < lidar_end_time)
- {
- return false;
- }
- /*** push imu data, and pop from imu buffer ***/
- double imu_time = imu_buffer.front()->header.stamp.toSec(); // 最旧IMU时间
- meas.imu.clear();
- while ((!imu_buffer.empty()) && (imu_time < lidar_end_time)) //记录imu数据,imu时间小于当前帧lidar结束时间
- {
- imu_time = imu_buffer.front()->header.stamp.toSec();
- if (imu_time > lidar_end_time)
- break;
- meas.imu.push_back(imu_buffer.front()); //记录当前lidar帧内的imu数据到meas.imu
- imu_buffer.pop_front();
- }
- lidar_buffer.pop_front();
- time_buffer.pop_front();
- lidar_pushed = false;
- return true;
- }
- int process_increments = 0;
- void map_incremental()
- {
- PointVector PointToAdd; //需要加入到ikd-tree中的点云
- PointVector PointNoNeedDownsample; //加入ikd-tree时,不需要降采样的点云
- PointToAdd.reserve(feats_down_size);
- PointNoNeedDownsample.reserve(feats_down_size);
- //根据点与所在包围盒中心点的距离,分类是否需要降采样
- for (int i = 0; i < feats_down_size; i++)
- {
- /* transform to world frame */
- pointBodyToWorld(&(feats_down_body->points[i]), &(feats_down_world->points[i]));
- /* decide if need add to map */
- if (!Nearest_Points[i].empty() && flg_EKF_inited)
- {
- const PointVector &points_near = Nearest_Points[i];
- bool need_add = true;
- BoxPointType Box_of_Point;
- PointType downsample_result, mid_point;
- mid_point.x = floor(feats_down_world->points[i].x / filter_size_map_min) * filter_size_map_min + 0.5 * filter_size_map_min;
- mid_point.y = floor(feats_down_world->points[i].y / filter_size_map_min) * filter_size_map_min + 0.5 * filter_size_map_min;
- mid_point.z = floor(feats_down_world->points[i].z / filter_size_map_min) * filter_size_map_min + 0.5 * filter_size_map_min;
- float dist = calc_dist(feats_down_world->points[i], mid_point); //当前点与box中心的距离
- //判断最近点在x、y、z三个方向上,与中心的距离,判断是否加入时需要降采样
- if (fabs(points_near[0].x - mid_point.x) > 0.5 * filter_size_map_min && fabs(points_near[0].y - mid_point.y) > 0.5 * filter_size_map_min && fabs(points_near[0].z - mid_point.z) > 0.5 * filter_size_map_min)
- {
- PointNoNeedDownsample.push_back(feats_down_world->points[i]); //若三个方向距离都大于地图珊格半轴长,无需降采样
- continue;
- }
- //判断当前点的 NUM_MATCH_POINTS 个邻近点与包围盒中心的范围
- for (int readd_i = 0; readd_i < NUM_MATCH_POINTS; readd_i++)
- {
- if (points_near.size() < NUM_MATCH_POINTS)
- break;
- if (calc_dist(points_near[readd_i], mid_point) < dist) // 如果邻近点到中心的距离 小于 当前点到中心的距离,则不需要添加当前点
- {
- need_add = false;
- break;
- }
- }
- if (need_add)
- PointToAdd.push_back(feats_down_world->points[i]);
- }
- else
- {
- PointToAdd.push_back(feats_down_world->points[i]);
- }
- }
- double st_time = omp_get_wtime();
- add_point_size = ikdtree.Add_Points(PointToAdd, true); //加入点时需要降采样
- ikdtree.Add_Points(PointNoNeedDownsample, false); //加入点时不需要降采样
- add_point_size = PointToAdd.size() + PointNoNeedDownsample.size();
- kdtree_incremental_time = omp_get_wtime() - st_time;
- }
- PointCloudXYZI::Ptr pcl_wait_pub(new PointCloudXYZI(500000, 1));
- PointCloudXYZI::Ptr pcl_wait_save(new PointCloudXYZI());
- void publish_frame_world(const ros::Publisher &pubLaserCloudFull) // 将稠密点云从 imu convert to world
- {
- if (scan_pub_en)
- {
- PointCloudXYZI::Ptr laserCloudFullRes(dense_pub_en ? feats_undistort : feats_down_body);
- int size = laserCloudFullRes->points.size();
- PointCloudXYZI::Ptr laserCloudWorld(
- new PointCloudXYZI(size, 1));
- for (int i = 0; i < size; i++)
- {
- RGBpointBodyToWorld(&laserCloudFullRes->points[i],
- &laserCloudWorld->points[i]);
- }
- sensor_msgs::PointCloud2 laserCloudmsg;
- pcl::toROSMsg(*laserCloudWorld, laserCloudmsg);
- laserCloudmsg.header.stamp = ros::Time().fromSec(lidar_end_time);
- laserCloudmsg.header.frame_id = "camera_init";
- pubLaserCloudFull.publish(laserCloudmsg);
- publish_count -= PUBFRAME_PERIOD;
- }
- /**************** save map ****************/
- /* 1. make sure you have enough memories
- /* 2. noted that pcd save will influence the real-time performences **/
- if (pcd_save_en)
- {
- int size = feats_undistort->points.size();
- PointCloudXYZI::Ptr laserCloudWorld(
- new PointCloudXYZI(size, 1));
- for (int i = 0; i < size; i++)
- {
- RGBpointBodyToWorld(&feats_undistort->points[i],
- &laserCloudWorld->points[i]);
- }
- *pcl_wait_save += *laserCloudWorld;
- static int scan_wait_num = 0;
- scan_wait_num++;
- if (pcl_wait_save->size() > 0 && pcd_save_interval > 0 && scan_wait_num >= pcd_save_interval)
- {
- pcd_index++;
- string all_points_dir(string(string(ROOT_DIR) + "PCD/scans_") + to_string(pcd_index) + string(".pcd"));
- pcl::PCDWriter pcd_writer;
- cout << "current scan saved to /PCD/" << all_points_dir << endl;
- pcd_writer.writeBinary(all_points_dir, *pcl_wait_save);
- pcl_wait_save->clear();
- scan_wait_num = 0;
- }
- }
- }
- void publish_frame_body(const ros::Publisher &pubLaserCloudFull_body) // 发布body系(imu)下的点云
- {
- int size = feats_undistort->points.size();
- PointCloudXYZI::Ptr laserCloudIMUBody(new PointCloudXYZI(size, 1));
- for (int i = 0; i < size; i++)
- {
- RGBpointBodyLidarToIMU(&feats_undistort->points[i],
- &laserCloudIMUBody->points[i]);
- }
- sensor_msgs::PointCloud2 laserCloudmsg;
- pcl::toROSMsg(*laserCloudIMUBody, laserCloudmsg);
- laserCloudmsg.header.stamp = ros::Time().fromSec(lidar_end_time);
- laserCloudmsg.header.frame_id = "body";
- pubLaserCloudFull_body.publish(laserCloudmsg);
- publish_count -= PUBFRAME_PERIOD;
- }
- void publish_effect_world(const ros::Publisher &pubLaserCloudEffect)
- {
- PointCloudXYZI::Ptr laserCloudWorld(
- new PointCloudXYZI(effct_feat_num, 1));
- for (int i = 0; i < effct_feat_num; i++)
- {
- RGBpointBodyToWorld(&laserCloudOri->points[i],
- &laserCloudWorld->points[i]);
- }
- sensor_msgs::PointCloud2 laserCloudFullRes3;
- pcl::toROSMsg(*laserCloudWorld, laserCloudFullRes3);
- laserCloudFullRes3.header.stamp = ros::Time().fromSec(lidar_end_time);
- laserCloudFullRes3.header.frame_id = "camera_init";
- pubLaserCloudEffect.publish(laserCloudFullRes3);
- }
- void publish_map(const ros::Publisher &pubLaserCloudMap)
- {
- sensor_msgs::PointCloud2 laserCloudMap;
- pcl::toROSMsg(*featsFromMap, laserCloudMap);
- laserCloudMap.header.stamp = ros::Time().fromSec(lidar_end_time);
- laserCloudMap.header.frame_id = "camera_init";
- pubLaserCloudMap.publish(laserCloudMap);
- }
- template <typename T>
- void set_posestamp(T &out)
- {
- out.pose.position.x = state_point.pos(0);
- out.pose.position.y = state_point.pos(1);
- out.pose.position.z = state_point.pos(2);
- out.pose.orientation.x = geoQuat.x;
- out.pose.orientation.y = geoQuat.y;
- out.pose.orientation.z = geoQuat.z;
- out.pose.orientation.w = geoQuat.w;
- }
- void publish_odometry(const ros::Publisher &pubOdomAftMapped)
- {
- odomAftMapped.header.frame_id = "camera_init";
- odomAftMapped.child_frame_id = "body";
- odomAftMapped.header.stamp = ros::Time().fromSec(lidar_end_time); // ros::Time().fromSec(lidar_end_time);
- set_posestamp(odomAftMapped.pose);
- pubOdomAftMapped.publish(odomAftMapped);
- auto P = ikfom_.get_P();
- for (int i = 0; i < 6; i++)
- {
- int k = i < 3 ? i + 3 : i - 3;
- odomAftMapped.pose.covariance[i * 6 + 0] = P(k, 3);
- odomAftMapped.pose.covariance[i * 6 + 1] = P(k, 4);
- odomAftMapped.pose.covariance[i * 6 + 2] = P(k, 5);
- odomAftMapped.pose.covariance[i * 6 + 3] = P(k, 0);
- odomAftMapped.pose.covariance[i * 6 + 4] = P(k, 1);
- odomAftMapped.pose.covariance[i * 6 + 5] = P(k, 2);
- }
- static tf::TransformBroadcaster br;
- tf::Transform transform;
- tf::Quaternion q;
- transform.setOrigin(tf::Vector3(odomAftMapped.pose.pose.position.x,
- odomAftMapped.pose.pose.position.y,
- odomAftMapped.pose.pose.position.z));
- q.setW(odomAftMapped.pose.pose.orientation.w);
- q.setX(odomAftMapped.pose.pose.orientation.x);
- q.setY(odomAftMapped.pose.pose.orientation.y);
- q.setZ(odomAftMapped.pose.pose.orientation.z);
- transform.setRotation(q);
- br.sendTransform(tf::StampedTransform(transform, odomAftMapped.header.stamp, "camera_init", "body"));
- }
- void publish_path(const ros::Publisher pubPath)
- {
- set_posestamp(msg_body_pose);
- msg_body_pose.header.stamp = ros::Time().fromSec(lidar_end_time);
- msg_body_pose.header.frame_id = "camera_init";
- /*** if path is too large, the rvis will crash ***/
- static int jjj = 0;
- jjj++;
- if (jjj % 10 == 0)
- {
- path.poses.push_back(msg_body_pose);
- pubPath.publish(path);
-
- // save unoptimized pose
- V3D rot_ang(Log( state_point.rot.toRotationMatrix())); // 旋转向量
- PointTypePose thisPose6D;
- thisPose6D.x = msg_body_pose.pose.position.x ;
- thisPose6D.y = msg_body_pose.pose.position.y ;
- thisPose6D.z = msg_body_pose.pose.position.z ;
- thisPose6D.roll = rot_ang(0) ;
- thisPose6D.pitch = rot_ang(1) ;
- thisPose6D.yaw = rot_ang(2) ;
- fastlio_unoptimized_cloudKeyPoses6D->push_back(thisPose6D);
- }
- }
- void publish_path_update(const ros::Publisher pubPath)
- {
- ros::Time timeLaserInfoStamp = ros::Time().fromSec(lidar_end_time); // 时间戳
- string odometryFrame = "camera_init";
- if (pubPath.getNumSubscribers() != 0)
- {
- /*** if path is too large, the rvis will crash ***/
- static int kkk = 0;
- kkk++;
- if (kkk % 10 == 0)
- {
- // path.poses.push_back(globalPath);
- globalPath.header.stamp = timeLaserInfoStamp;
- globalPath.header.frame_id = odometryFrame;
- pubPath.publish(globalPath);
- }
- }
- }
- /*定义pose结构体*/
- struct pose
- {
- Eigen::Vector3d t ;
- Eigen::Matrix3d R;
- };
- bool CreateFile(std::ofstream& ofs, std::string file_path) {
- ofs.open(file_path, std::ios::out); // 使用std::ios::out 可实现覆盖
- if(!ofs)
- {
- std::cout << "open csv file error " << std::endl;
- return false;
- }
- return true;
- }
- /* write2txt format KITTI*/
- void WriteText(std::ofstream& ofs, pose data){
- ofs << std::fixed << data.R(0,0) << " " << data.R(0,1) << " "<< data.R(0,2) << " " << data.t[0] << " "
- << data.R(1,0) << " " << data.R(1,1) <<" " << data.R(1,2) << " " << data.t[1] << " "
- << data.R(2,0) << " " << data.R(2,1) <<" " << data.R(2,2) << " " << data.t[2] << std::endl;
- }
- bool savePoseService(fast_lio_sam::save_poseRequest& req, fast_lio_sam::save_poseResponse& res)
- {
- pose pose_gnss ;
- pose pose_optimized ;
- pose pose_without_optimized ;
- //std::ofstream file_pose_gnss ;
- std::ofstream file_pose_optimized ;
- std::ofstream file_pose_without_optimized ;
- string savePoseDirectory;
- cout << "****************************************************" << endl;
- cout << "Saving poses to pose files ..." << endl;
- if(req.destination.empty()) savePoseDirectory = std::getenv("HOME") + savePCDDirectory;
- else savePoseDirectory = std::getenv("HOME") + req.destination;
- cout << "Save destination: " << savePoseDirectory << endl;
- // create file
- // CreateFile(file_pose_gnss, savePoseDirectory + "/gnss_pose.txt");
- CreateFile(file_pose_optimized, savePoseDirectory + "/optimized_pose.txt");
- CreateFile(file_pose_without_optimized, savePoseDirectory + "/without_optimized_pose.txt");
- // save optimize data
- for(int i = 0; i < cloudKeyPoses6D->size(); i++){
- pose_optimized.t = Eigen::Vector3d(cloudKeyPoses6D->points[i].x, cloudKeyPoses6D->points[i].y, cloudKeyPoses6D->points[i].z );
- pose_optimized.R = Exp(double(cloudKeyPoses6D->points[i].roll), double(cloudKeyPoses6D->points[i].pitch), double(cloudKeyPoses6D->points[i].yaw) );
- WriteText(file_pose_optimized, pose_optimized);
- }
- cout << "Sucess global optimized poses to pose files ..." << endl;
- for(int i = 0; i < fastlio_unoptimized_cloudKeyPoses6D->size(); i++){
- pose_without_optimized.t = Eigen::Vector3d(fastlio_unoptimized_cloudKeyPoses6D->points[i].x, fastlio_unoptimized_cloudKeyPoses6D->points[i].y, fastlio_unoptimized_cloudKeyPoses6D->points[i].z );
- pose_without_optimized.R = Exp(double(fastlio_unoptimized_cloudKeyPoses6D->points[i].roll), double(fastlio_unoptimized_cloudKeyPoses6D->points[i].pitch), double(fastlio_unoptimized_cloudKeyPoses6D->points[i].yaw) );
- WriteText(file_pose_without_optimized, pose_without_optimized);
- }
- cout << "Sucess unoptimized poses to pose files ..." << endl;
- //file_pose_gnss.close();
- file_pose_optimized.close();
- file_pose_without_optimized.close();
- return true ;
- }
- /**
- * 保存全局关键帧特征点集合
- */
- bool saveMapService(fast_lio_sam::save_mapRequest& req, fast_lio_sam::save_mapResponse& res)
- {
- string saveMapDirectory;
-
- cout << "****************************************************" << endl;
- cout << "Saving map to pcd files ..." << endl;
- if(req.destination.empty()) saveMapDirectory = std::getenv("HOME") + savePCDDirectory;
- else saveMapDirectory = std::getenv("HOME") + req.destination;
- cout << "Save destination: " << saveMapDirectory << endl;
- // 这个代码太坑了!!注释掉
- // int unused = system((std::string("exec rm -r ") + saveMapDirectory).c_str());
- // unused = system((std::string("mkdir -p ") + saveMapDirectory).c_str());
- // 保存历史关键帧位姿
- pcl::io::savePCDFileBinary(saveMapDirectory + "/trajectory.pcd", *cloudKeyPoses3D); // 关键帧位置
- pcl::io::savePCDFileBinary(saveMapDirectory + "/transformations.pcd", *cloudKeyPoses6D); // 关键帧位姿
- // 提取历史关键帧点集合
- pcl::PointCloud<PointType>::Ptr globalSurfCloud(new pcl::PointCloud<PointType>());
- pcl::PointCloud<PointType>::Ptr globalSurfCloudDS(new pcl::PointCloud<PointType>());
- pcl::PointCloud<PointType>::Ptr globalMapCloud(new pcl::PointCloud<PointType>());
- // 注意:拼接地图时,keyframe是lidar系,而fastlio更新后的存到的cloudKeyPoses6D 关键帧位姿是body系下的,需要把
- //cloudKeyPoses6D 转换为T_world_lidar 。 T_world_lidar = T_world_body * T_body_lidar , T_body_lidar 是外参
- for (int i = 0; i < (int)cloudKeyPoses6D->size(); i++) {
- // *globalCornerCloud += *transformPointCloud(cornerCloudKeyFrames[i], &cloudKeyPoses6D->points[i]);
- *globalSurfCloud += *transformPointCloud(surfCloudKeyFrames[i], &cloudKeyPoses6D->points[i]);
- cout << "\r" << std::flush << "Processing feature cloud " << i << " of " << cloudKeyPoses6D->size() << " ...";
- }
- if(req.resolution != 0)
- {
- cout << "\n\nSave resolution: " << req.resolution << endl;
- // 降采样
- downSizeFilterSurf.setInputCloud(globalSurfCloud);
- downSizeFilterSurf.setLeafSize(req.resolution, req.resolution, req.resolution);
- downSizeFilterSurf.filter(*globalSurfCloudDS);
- pcl::io::savePCDFileBinary(saveMapDirectory + "/SurfMap.pcd", *globalSurfCloudDS);
- }
- else
- {
- // downSizeFilterCorner.setLeafSize(mappingCornerLeafSize, mappingCornerLeafSize, mappingCornerLeafSize);
- downSizeFilterSurf.setInputCloud(globalSurfCloud);
- downSizeFilterSurf.setLeafSize(mappingSurfLeafSize, mappingSurfLeafSize, mappingSurfLeafSize);
- downSizeFilterSurf.filter(*globalSurfCloudDS);
- // pcl::io::savePCDFileBinary(saveMapDirectory + "/CornerMap.pcd", *globalCornerCloud);
- // pcl::io::savePCDFileBinary(saveMapDirectory + "/SurfMap.pcd", *globalSurfCloud); // 稠密点云地图
- }
- // 保存到一起,全局关键帧特征点集合
- // *globalMapCloud += *globalCornerCloud;
- *globalMapCloud += *globalSurfCloud;
- pcl::io::savePCDFileBinary(saveMapDirectory + "/filterGlobalMap.pcd", *globalSurfCloudDS); // 滤波后地图
- int ret = pcl::io::savePCDFileBinary(saveMapDirectory + "/GlobalMap.pcd", *globalMapCloud); // 稠密地图
- res.success = ret == 0;
- cout << "****************************************************" << endl;
- cout << "Saving map to pcd files completed\n" << endl;
- // visial optimize global map on viz
- ros::Time timeLaserInfoStamp = ros::Time().fromSec(lidar_end_time);
- string odometryFrame = "camera_init";
- publishCloud(&pubOptimizedGlobalMap, globalSurfCloudDS, timeLaserInfoStamp, odometryFrame);
- return true;
- }
- void saveMap()
- {
- fast_lio_sam::save_mapRequest req;
- fast_lio_sam::save_mapResponse res;
- // 保存全局关键帧特征点集合
- if(!saveMapService(req, res)){
- cout << "Fail to save map" << endl;
- }
- }
- /**
- * 发布局部关键帧map的特征点云
- */
- void publishGlobalMap()
- {
- /*** if path is too large, the rvis will crash ***/
- ros::Time timeLaserInfoStamp = ros::Time().fromSec(lidar_end_time);
- string odometryFrame = "camera_init";
- if (pubLaserCloudSurround.getNumSubscribers() == 0)
- return;
- if (cloudKeyPoses3D->points.empty() == true)
- return;
- pcl::KdTreeFLANN<PointType>::Ptr kdtreeGlobalMap(new pcl::KdTreeFLANN<PointType>());
- ;
- pcl::PointCloud<PointType>::Ptr globalMapKeyPoses(new pcl::PointCloud<PointType>());
- pcl::PointCloud<PointType>::Ptr globalMapKeyPosesDS(new pcl::PointCloud<PointType>());
- pcl::PointCloud<PointType>::Ptr globalMapKeyFrames(new pcl::PointCloud<PointType>());
- pcl::PointCloud<PointType>::Ptr globalMapKeyFramesDS(new pcl::PointCloud<PointType>());
- // kdtree查找最近一帧关键帧相邻的关键帧集合
- std::vector<int> pointSearchIndGlobalMap;
- std::vector<float> pointSearchSqDisGlobalMap;
- mtx.lock();
- kdtreeGlobalMap->setInputCloud(cloudKeyPoses3D);
- kdtreeGlobalMap->radiusSearch(cloudKeyPoses3D->back(), globalMapVisualizationSearchRadius, pointSearchIndGlobalMap, pointSearchSqDisGlobalMap, 0);
- mtx.unlock();
- for (int i = 0; i < (int)pointSearchIndGlobalMap.size(); ++i)
- globalMapKeyPoses->push_back(cloudKeyPoses3D->points[pointSearchIndGlobalMap[i]]);
- // 降采样
- pcl::VoxelGrid<PointType> downSizeFilterGlobalMapKeyPoses;
- downSizeFilterGlobalMapKeyPoses.setLeafSize(globalMapVisualizationPoseDensity, globalMapVisualizationPoseDensity, globalMapVisualizationPoseDensity); // for global map visualization
- downSizeFilterGlobalMapKeyPoses.setInputCloud(globalMapKeyPoses);
- downSizeFilterGlobalMapKeyPoses.filter(*globalMapKeyPosesDS);
- // 提取局部相邻关键帧对应的特征点云
- for (int i = 0; i < (int)globalMapKeyPosesDS->size(); ++i)
- {
- // 距离过大
- if (pointDistance(globalMapKeyPosesDS->points[i], cloudKeyPoses3D->back()) > globalMapVisualizationSearchRadius)
- continue;
- int thisKeyInd = (int)globalMapKeyPosesDS->points[i].intensity;
- // *globalMapKeyFrames += *transformPointCloud(cornerCloudKeyFrames[thisKeyInd], &cloudKeyPoses6D->points[thisKeyInd]);
- *globalMapKeyFrames += *transformPointCloud(surfCloudKeyFrames[thisKeyInd], &cloudKeyPoses6D->points[thisKeyInd]); // fast_lio only use surfCloud
- }
- // 降采样,发布
- pcl::VoxelGrid<PointType> downSizeFilterGlobalMapKeyFrames; // for global map visualization
- downSizeFilterGlobalMapKeyFrames.setLeafSize(globalMapVisualizationLeafSize, globalMapVisualizationLeafSize, globalMapVisualizationLeafSize); // for global map visualization
- downSizeFilterGlobalMapKeyFrames.setInputCloud(globalMapKeyFrames);
- downSizeFilterGlobalMapKeyFrames.filter(*globalMapKeyFramesDS);
- publishCloud(&pubLaserCloudSurround, globalMapKeyFramesDS, timeLaserInfoStamp, odometryFrame);
- }
- //构造H矩阵
- void h_share_model(state_ikfom &s, esekfom::dyn_share_datastruct<double> &ekfom_data)
- {
- double match_start = omp_get_wtime();
- laserCloudOri->clear();
- corr_normvect->clear();
- total_residual = 0.0;
- /** closest surface search and residual computation **/
- #ifdef MP_EN
- omp_set_num_threads(MP_PROC_NUM);
- #pragma omp parallel for
- #endif
- for (int i = 0; i < feats_down_size; i++) //判断每个点的对应邻域是否符合平面点的假设
- {
- PointType &point_body = feats_down_body->points[i]; // lidar系下坐标
- PointType &point_world = feats_down_world->points[i]; // lidar数据点在world系下坐标
- /* transform to world frame */
- V3D p_body(point_body.x, point_body.y, point_body.z); // lidar系下坐标
- V3D p_global(s.rot * (s.offset_R_L_I * p_body + s.offset_T_L_I) + s.pos); // w系下坐标
- point_world.x = p_global(0);
- point_world.y = p_global(1);
- point_world.z = p_global(2);
- point_world.intensity = point_body.intensity;
- vector<float> pointSearchSqDis(NUM_MATCH_POINTS);
- auto &points_near = Nearest_Points[i];
- if (ekfom_data.converge) // 如果收敛了
- {
- /** Find the closest surfaces in the map **/
- // world系下从ikdtree找5个最近点用于平面拟合
- ikdtree.Nearest_Search(point_world, NUM_MATCH_POINTS, points_near, pointSearchSqDis);
- //最近点数大于NUM_MATCH_POINTS,且最大距离小于等于5,point_selected_surf设置为true
- point_selected_surf[i] = points_near.size() < NUM_MATCH_POINTS ? false : pointSearchSqDis[NUM_MATCH_POINTS - 1] > 5 ? false
- : true;
- }
- //不符合平面特征
- if (!point_selected_surf[i])
- continue;
- VF(4) pabcd; // plane 参数 a b c d
- point_selected_surf[i] = false; //二次筛选平面点
- //拟合局部平面,返回:是否有内点大于距离阈值
- if (esti_plane(pabcd, points_near, 0.1f))
- {
- // plane distance
- float pd2 = pabcd(0) * point_world.x + pabcd(1) * point_world.y + pabcd(2) * point_world.z + pabcd(3);
- float s = 1 - 0.9 * fabs(pd2) / sqrt(p_body.norm()); //筛选条件 1 - 0.9 * (点到平面距离 / 点到lidar原点距离)
- if (s > 0.9)
- {
- point_selected_surf[i] = true;
- normvec->points[i].x = pabcd(0);
- normvec->points[i].y = pabcd(1);
- normvec->points[i].z = pabcd(2);
- normvec->points[i].intensity = pd2; //以intensity记录点到面残差
- res_last[i] = abs(pd2); // 残差,距离
- }
- }
- }
- effct_feat_num = 0; //有效匹配点数
- for (int i = 0; i < feats_down_size; i++)
- {
- if (point_selected_surf[i])
- {
- laserCloudOri->points[effct_feat_num] = feats_down_body->points[i]; // body系 平面特征点
- corr_normvect->points[effct_feat_num] = normvec->points[i]; // world系 平面参数
- total_residual += res_last[i]; // 残差和
- effct_feat_num++;
- }
- }
- if (effct_feat_num < 1)
- {
- ekfom_data.valid = false;
- ROS_WARN("No Effective Points! \n");
- return;
- }
- res_mean_last = total_residual / effct_feat_num; // 残差均值 (距离)
- match_time += omp_get_wtime() - match_start;
- double solve_start_ = omp_get_wtime();
- /*** Computation of Measuremnt Jacobian matrix H and measurents vector ***/
- ekfom_data.h_x = MatrixXd::Zero(effct_feat_num, 12); //定义H维度
- ekfom_data.h.resize(effct_feat_num); //有效方程个数
- for (int i = 0; i < effct_feat_num; i++)
- {
- const PointType &laser_p = laserCloudOri->points[i]; // lidar系 平面特征点
- V3D point_this_be(laser_p.x, laser_p.y, laser_p.z);
- M3D point_be_crossmat;
- point_be_crossmat << SKEW_SYM_MATRX(point_this_be);
- V3D point_this = s.offset_R_L_I * point_this_be + s.offset_T_L_I; // 当前状态imu系下 点坐标
- M3D point_crossmat;
- point_crossmat << SKEW_SYM_MATRX(point_this); // 当前状态imu系下 点坐标反对称矩阵
- /*** get the normal vector of closest surface/corner ***/
- const PointType &norm_p = corr_normvect->points[i];
- V3D norm_vec(norm_p.x, norm_p.y, norm_p.z); //对应局部法相量, world系下
- /*** calculate the Measuremnt Jacobian matrix H ***/
- V3D C(s.rot.conjugate() * norm_vec); // 将对应局部法相量旋转到imu系下 corr_normal_I
- V3D A(point_crossmat * C); //残差对角度求导系数 P(IMU)^ [R(imu <-- w) * normal_w]
- //添加数据到矩阵
- if (extrinsic_est_en)
- {
- // B = lidar_p^ R(L <-- I) * corr_normal_I
- // B = lidar_p^ R(L <-- I) * R(I <-- W) * normal_W
- V3D B(point_be_crossmat * s.offset_R_L_I.conjugate() * C); // s.rot.conjugate()*norm_vec);
- ekfom_data.h_x.block<1, 12>(i, 0) << norm_p.x, norm_p.y, norm_p.z, VEC_FROM_ARRAY(A), VEC_FROM_ARRAY(B), VEC_FROM_ARRAY(C);
- }
- else
- {
- ekfom_data.h_x.block<1, 12>(i, 0) << norm_p.x, norm_p.y, norm_p.z, VEC_FROM_ARRAY(A), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0;
- }
- /*** Measuremnt: distance to the closest surface/corner ***/
- ekfom_data.h(i) = -norm_p.intensity;
- }
- 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();
- for (int i = 0; i < 6; ++i) {
- transformTobeMapped[i] = 0;
- }
- ros::init(argc, argv, "laserMapping");
- ros::NodeHandle nh;
- nh.param<bool>("publish/path_en", path_en, true);
- 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, 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");
- nh.param<bool>("common/time_sync_en", time_sync_en, false);
- nh.param<double>("filter_size_corner", filter_size_corner_min, 0.5);
- nh.param<double>("filter_size_surf", filter_size_surf_min, 0.5);
- nh.param<double>("filter_size_map", filter_size_map_min, 0.5);
- nh.param<double>("cube_side_length", cube_len, 200);
- nh.param<float>("mapping/det_range", DET_RANGE, 300.f);
- nh.param<double>("mapping/fov_degree", fov_deg, 180);
- nh.param<double>("mapping/gyr_cov", gyr_cov, 0.1);
- nh.param<double>("mapping/acc_cov", acc_cov, 0.1);
- nh.param<double>("mapping/b_gyr_cov", b_gyr_cov, 0.0001);
- nh.param<double>("mapping/b_acc_cov", b_acc_cov, 0.0001);
- nh.param<double>("preprocess/blind", p_pre->blind, 0.01);
- 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, 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);
- nh.param<bool>("pcd_save/pcd_save_en", pcd_save_en, false);
- nh.param<int>("pcd_save/interval", pcd_save_interval, -1);
- nh.param<vector<double>>("mapping/extrinsic_T", extrinT, vector<double>());
- nh.param<vector<double>>("mapping/extrinsic_R", extrinR, vector<double>());
- cout << "p_pre->lidar_type " << p_pre->lidar_type << endl;
- nh.param<float>("odometrySurfLeafSize", odometrySurfLeafSize, 0.2);
- nh.param<float>("mappingCornerLeafSize", mappingCornerLeafSize, 0.2);
- nh.param<float>("mappingSurfLeafSize", mappingSurfLeafSize, 0.2);
- nh.param<float>("z_tollerance", z_tollerance, FLT_MAX);
- nh.param<float>("rotation_tollerance", rotation_tollerance, FLT_MAX);
- nh.param<int>("numberOfCores", numberOfCores, 2);
- nh.param<double>("mappingProcessInterval", mappingProcessInterval, 0.15);
- // save keyframes
- nh.param<float>("surroundingkeyframeAddingDistThreshold", surroundingkeyframeAddingDistThreshold, 20.0);
- nh.param<float>("surroundingkeyframeAddingAngleThreshold", surroundingkeyframeAddingAngleThreshold, 0.2);
- nh.param<float>("surroundingKeyframeDensity", surroundingKeyframeDensity, 1.0);
- nh.param<float>("surroundingKeyframeSearchRadius", surroundingKeyframeSearchRadius, 50.0);
- // loop clousre
- nh.param<bool>("loopClosureEnableFlag", loopClosureEnableFlag, false);
- nh.param<float>("loopClosureFrequency", loopClosureFrequency, 1.0);
- nh.param<int>("surroundingKeyframeSize", surroundingKeyframeSize, 50);
- nh.param<float>("historyKeyframeSearchRadius", historyKeyframeSearchRadius, 10.0);
- nh.param<float>("historyKeyframeSearchTimeDiff", historyKeyframeSearchTimeDiff, 30.0);
- nh.param<int>("historyKeyframeSearchNum", historyKeyframeSearchNum, 25);
- nh.param<float>("historyKeyframeFitnessScore", historyKeyframeFitnessScore, 0.3);
- // Visualization
- nh.param<float>("globalMapVisualizationSearchRadius", globalMapVisualizationSearchRadius, 1e3);
- nh.param<float>("globalMapVisualizationPoseDensity", globalMapVisualizationPoseDensity, 10.0);
- nh.param<float>("globalMapVisualizationLeafSize", globalMapVisualizationLeafSize, 1.0);
- // 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);
- // savMap
- nh.param<bool>("savePCD", savePCD, false);
- nh.param<std::string>("savePCDDirectory", savePCDDirectory, "/Downloads/LOAM/");
- downSizeFilterCorner.setLeafSize(mappingCornerLeafSize, mappingCornerLeafSize, mappingCornerLeafSize);
- // downSizeFilterSurf.setLeafSize(mappingSurfLeafSize, mappingSurfLeafSize, mappingSurfLeafSize);
- downSizeFilterICP.setLeafSize(mappingSurfLeafSize, mappingSurfLeafSize, mappingSurfLeafSize);
- downSizeFilterSurroundingKeyPoses.setLeafSize(surroundingKeyframeDensity, surroundingKeyframeDensity,
- surroundingKeyframeDensity); // for surrounding key poses of scan-to-map optimization
- /*
- * SC回环参数
- */
- scManager.setSCdistThres(scDistThres);
- scManager.setMaximumRadius(scMaximumRadius);
- // ISAM2参数
- gtsam::ISAM2Params parameters;
- parameters.relinearizeThreshold = 0.01;
- parameters.relinearizeSkip = 1;
- isam = new gtsam::ISAM2(parameters);
- path.header.stamp = ros::Time::now();
- path.header.frame_id = "camera_init";
- /*** variables definition ***/
- int effect_feat_num = 0, frame_num = 0;
- double deltaT, deltaR, aver_time_consu = 0, aver_time_icp = 0, aver_time_match = 0, aver_time_incre = 0, aver_time_solve = 0, aver_time_const_H_time = 0;
- bool flg_EKF_converged, EKF_stop_flg = 0;
- FOV_DEG = (fov_deg + 10.0) > 179.9 ? 179.9 : (fov_deg + 10.0);
- HALF_FOV_COS = cos((FOV_DEG) * 0.5 * PI_M / 180.0);
- _featsArray.reset(new PointCloudXYZI());
- memset(point_selected_surf, true, sizeof(point_selected_surf));
- memset(res_last, -1000.0f, sizeof(res_last));
- downSizeFilterSurf.setLeafSize(filter_size_surf_min, filter_size_surf_min, filter_size_surf_min);
- downSizeFilterMap.setLeafSize(filter_size_map_min, filter_size_map_min, filter_size_map_min);
- memset(point_selected_surf, true, sizeof(point_selected_surf)); //重复?
- memset(res_last, -1000.0f, sizeof(res_last));
- //设置imu和lidar外参和imu参数等
- Lidar_T_wrt_IMU << VEC_FROM_ARRAY(extrinT);
- Lidar_R_wrt_IMU << MAT_FROM_ARRAY(extrinR);
- p_imu->set_extrinsic(Lidar_T_wrt_IMU, Lidar_R_wrt_IMU);
- p_imu->set_gyr_cov(V3D(gyr_cov, gyr_cov, gyr_cov));
- p_imu->set_acc_cov(V3D(acc_cov, acc_cov, acc_cov)); // 加速度协方差
- p_imu->set_gyr_bias_cov(V3D(b_gyr_cov, b_gyr_cov, b_gyr_cov));
- p_imu->set_acc_bias_cov(V3D(b_acc_cov, b_acc_cov, b_acc_cov));
- double epsi[23] = {0.001};
- fill(epsi, epsi + 23, 0.001);
- ///初始化,其中h_share_model定义了·平面搜索和残差计算
- ikfom_.init_dyn_share(get_f, df_dx, df_dw, h_share_model, NUM_MAX_ITERATIONS, epsi);
- /*** debug record ***/
- FILE *fp;
- string pos_log_dir = root_dir + "/Log/pos_log.txt";
- fp = fopen(pos_log_dir.c_str(), "w");
- ofstream fout_pre, fout_out, fout_dbg;
- fout_pre.open(DEBUG_FILE_DIR("mat_pre.txt"), ios::out);
- fout_out.open(DEBUG_FILE_DIR("mat_out.txt"), ios::out);
- fout_dbg.open(DEBUG_FILE_DIR("dbg.txt"), ios::out);
- if (fout_pre && fout_out)
- cout << "~~~~" << ROOT_DIR << " file opened" << endl;
- else
- cout << "~~~~" << ROOT_DIR << " doesn't exist" << endl;
- /*** ROS subscribe initialization ***/
- ros::Subscriber sub_pcl =
- p_pre->lidar_type == AVIA ? nh.subscribe(lid_topic, 200000, livox_pcl_cbk) : nh.subscribe(lid_topic, 200000,
- standard_pcl_cbk);
- ros::Subscriber sub_imu = nh.subscribe(imu_topic, 200000, imu_cbk);
- ros::Publisher pubLaserCloudFull = nh.advertise<sensor_msgs::PointCloud2>("/cloud_registered",
- 100000); // world系下稠密点云
- ros::Publisher pubLaserCloudFull_body = nh.advertise<sensor_msgs::PointCloud2>("/cloud_registered_body",
- 100000); // body系下稠密点云
- ros::Publisher pubLaserCloudEffect = nh.advertise<sensor_msgs::PointCloud2>("/cloud_effected",
- 100000); // no used
- ros::Publisher pubLaserCloudMap = nh.advertise<sensor_msgs::PointCloud2>("/Laser_map",
- 100000); // no used
- ros::Publisher pubOdomAftMapped = nh.advertise<nav_msgs::Odometry>("/Odometry", 100000);
- ros::Publisher pubPath = nh.advertise<nav_msgs::Path>("/path", 1e00000);
- ros::Publisher pubPathUpdate = nh.advertise<nav_msgs::Path>("fast_lio_sam/path_update",
- 100000); // isam更新后的path
- pubLaserCloudSurround = nh.advertise<sensor_msgs::PointCloud2>("fast_lio_sam/mapping/keyframe_submap",
- 1); // 发布局部关键帧map的特征点云
- pubOptimizedGlobalMap = nh.advertise<sensor_msgs::PointCloud2>("fast_lio_sam/mapping/map_global_optimized",
- 1); // 发布局部关键帧map的特征点云
- // loop clousre
- // 发布闭环匹配关键帧局部map
- pubHistoryKeyFrames = nh.advertise<sensor_msgs::PointCloud2>("fast_lio_sam/mapping/icp_loop_closure_history_cloud",
- 1);
- // 发布当前关键帧经过闭环优化后的位姿变换之后的特征点云
- pubIcpKeyFrames = nh.advertise<sensor_msgs::PointCloud2>("fast_lio_sam/mapping/icp_loop_closure_corrected_cloud", 1);
- // 发布闭环边,rviz中表现为闭环帧之间的连线
- pubLoopConstraintEdge = nh.advertise<visualization_msgs::MarkerArray>(
- "/fast_lio_sam/mapping/loop_closure_constraints", 1);
- ros::Subscriber sub_init_pose;
- // 回环检测线程
- 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
- {
- PCL_ERROR ("Couldn't read file test_pcd.pcd \n"); //文件不存在时,返回错误,终止程序。
- return (-1);
- }
- printf(" Read map point num:%d\n", map_cloud.size());
- ikdtree.Build(map_cloud.points);
- 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)) {
- 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;
- 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位置
- if (feats_undistort->empty() || (feats_undistort == NULL)) {
- ROS_WARN("No point, skip this scan!\n");
- ikf_lock_.unlock();
- continue;
- }
- // 检查当前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());
- }
- 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);
- }
- ikf_lock_.unlock();
- continue;
- }
- }
- int featsFromMapNum = ikdtree.validnum();
- kdtree_size_st = ikdtree.size();
- // cout<<"[ mapping ]: In num: "<<feats_undistort->points.size()<<" downsamp "<<feats_down_size<<" Map num: "<<featsFromMapNum<<"effect num:"<<effct_feat_num<<endl;
- /*** 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(); // 发布局部点云特征地图
- }
- }
- if (scan_pub_en && scan_body_pub_en)
- publish_frame_body(pubLaserCloudFull_body); // 发布imu系下的点云
- /*
- //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);
- }*/
- }
- status = ros::ok();
- rate.sleep();
- }
- /**************** 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);
- }
- 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]);
- }
- fclose(fp2);
- }
- startFlag = false;
- if (locate_mode == false) {
- loopthread->join(); // 分离线程
- }
- delete loopthread;
- return 0;
- }
|