|
|
@@ -0,0 +1,423 @@
|
|
|
+//
|
|
|
+// Created by zx on 22-10-31.
|
|
|
+//
|
|
|
+
|
|
|
+#include "map_node.h"
|
|
|
+#include <tf/transform_broadcaster.h>
|
|
|
+#include <yaml-cpp/yaml.h>
|
|
|
+#include <execution>
|
|
|
+#include <fstream>
|
|
|
+#include <pcl/io/pcd_io.h>
|
|
|
+#include "utils.h"
|
|
|
+
|
|
|
+namespace faster_lio {
|
|
|
+
|
|
|
+bool Map_node::InitROS(ros::NodeHandle &nh) {
|
|
|
+ LoadParams(nh);
|
|
|
+ SubAndPubToROS(nh);
|
|
|
+
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+bool Map_node::LoadParams(ros::NodeHandle &nh) {
|
|
|
+ // get params from param server
|
|
|
+ int lidar_type, ivox_nearby_type;
|
|
|
+ double gyr_cov, acc_cov, b_gyr_cov, b_acc_cov;
|
|
|
+ double filter_size_surf_min;
|
|
|
+ common::V3D lidar_T_wrt_IMU;
|
|
|
+ common::M3D lidar_R_wrt_IMU;
|
|
|
+
|
|
|
+ nh.param<bool>("path_save_en", path_save_en_, true);
|
|
|
+ nh.param<bool>("publish/path_publish_en", path_pub_en_, true);
|
|
|
+ nh.param<bool>("publish/scan_publish_en", scan_pub_en_, true);
|
|
|
+ nh.param<bool>("publish/dense_publish_en", dense_pub_en_, false);
|
|
|
+ nh.param<bool>("publish/scan_bodyframe_pub_en", scan_body_pub_en_, true);
|
|
|
+ nh.param<bool>("publish/scan_effect_pub_en", scan_effect_pub_en_, false);
|
|
|
+
|
|
|
+ nh.param<int>("max_iteration", options::NUM_MAX_ITERATIONS, 4);
|
|
|
+ nh.param<float>("esti_plane_threshold", options::ESTI_PLANE_THRESHOLD, 0.1);
|
|
|
+ //nh.param<std::string>("map_file_path", map_file_path_, "");
|
|
|
+ nh.param<bool>("common/time_sync_en", mapper_.time_sync_en_, false);
|
|
|
+ nh.param<double>("filter_size_surf", filter_size_surf_min, 0.5);
|
|
|
+ nh.param<double>("filter_size_map", mapper_.filter_size_map_min_, 0.0);
|
|
|
+ nh.param<double>("cube_side_length", mapper_.cube_len_, 200);
|
|
|
+ nh.param<float>("mapping/det_range", mapper_.det_range_, 300.f);
|
|
|
+ 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", preprocess_->Blind(), 0.01);
|
|
|
+ nh.param<float>("preprocess/time_scale", preprocess_->TimeScale(), 1e-3);
|
|
|
+ nh.param<int>("preprocess/lidar_type", lidar_type, 1);
|
|
|
+ nh.param<int>("preprocess/scan_line", preprocess_->NumScans(), 16);
|
|
|
+ nh.param<int>("point_filter_num", preprocess_->PointFilterNum(), 2);
|
|
|
+ nh.param<bool>("feature_extract_enable", preprocess_->FeatureEnabled(), false);
|
|
|
+ nh.param<bool>("runtime_pos_log_enable", runtime_pos_log_, true);
|
|
|
+ nh.param<bool>("mapping/extrinsic_est_en", mapper_.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<std::vector<double>>("mapping/extrinsic_T", mapper_.extrinT_, std::vector<double>());
|
|
|
+ nh.param<std::vector<double>>("mapping/extrinsic_R", mapper_.extrinR_, std::vector<double>());
|
|
|
+
|
|
|
+ nh.param<float>("ivox_grid_resolution", mapper_.ivox_options_.resolution_, 0.2);
|
|
|
+ nh.param<int>("ivox_nearby_type", ivox_nearby_type, 18);
|
|
|
+
|
|
|
+
|
|
|
+ LOG(INFO) << "lidar_type " << lidar_type;
|
|
|
+ if (lidar_type == 1) {
|
|
|
+ preprocess_->SetLidarType(LidarType::AVIA);
|
|
|
+ LOG(INFO) << "Using AVIA Lidar";
|
|
|
+ } else if (lidar_type == 2) {
|
|
|
+ preprocess_->SetLidarType(LidarType::VELO32);
|
|
|
+ LOG(INFO) << "Using Velodyne 32 Lidar";
|
|
|
+ } else if (lidar_type == 3) {
|
|
|
+ preprocess_->SetLidarType(LidarType::OUST64);
|
|
|
+ LOG(INFO) << "Using OUST 64 Lidar";
|
|
|
+ } else {
|
|
|
+ LOG(WARNING) << "unknown lidar_type";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ mapper_.Init(ivox_nearby_type,gyr_cov,
|
|
|
+ acc_cov, b_gyr_cov, b_acc_cov,filter_size_surf_min);
|
|
|
+
|
|
|
+ path_.header.stamp = ros::Time::now();
|
|
|
+ path_.header.frame_id = "camera_init";
|
|
|
+
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void Map_node::SubAndPubToROS(ros::NodeHandle &nh) {
|
|
|
+ // ROS subscribe initialization
|
|
|
+ std::string lidar_topic, imu_topic;
|
|
|
+ nh.param<std::string>("common/lid_topic", lidar_topic, "/livox/lidar");
|
|
|
+ nh.param<std::string>("common/imu_topic", imu_topic, "/livox/imu");
|
|
|
+
|
|
|
+ if (preprocess_->GetLidarType() == LidarType::AVIA) {
|
|
|
+ sub_pcl_ = nh.subscribe<livox_ros_driver::CustomMsg>(
|
|
|
+ lidar_topic, 200000, [this](const livox_ros_driver::CustomMsg::ConstPtr &msg) { LivoxPCLCallBack(msg); });
|
|
|
+ } else {
|
|
|
+ sub_pcl_ = nh.subscribe<sensor_msgs::PointCloud2>(
|
|
|
+ lidar_topic, 200000, [this](const sensor_msgs::PointCloud2::ConstPtr &msg) { StandardPCLCallBack(msg); });
|
|
|
+ }
|
|
|
+
|
|
|
+ sub_imu_ = nh.subscribe<sensor_msgs::Imu>(imu_topic, 200000,
|
|
|
+ [this](const sensor_msgs::Imu::ConstPtr &msg) { IMUCallBack(msg); });
|
|
|
+
|
|
|
+ // ROS publisher init
|
|
|
+ path_.header.stamp = ros::Time::now();
|
|
|
+ path_.header.frame_id = "camera_init";
|
|
|
+
|
|
|
+ pub_laser_cloud_world_ = nh.advertise<sensor_msgs::PointCloud2>("/cloud_registered", 100000);
|
|
|
+ pub_laser_cloud_body_ = nh.advertise<sensor_msgs::PointCloud2>("/cloud_registered_body", 100000);
|
|
|
+ pub_laser_cloud_effect_world_ = nh.advertise<sensor_msgs::PointCloud2>("/cloud_registered_effect_world", 100000);
|
|
|
+ pub_odom_aft_mapped_ = nh.advertise<nav_msgs::Odometry>("/Odometry", 100000);
|
|
|
+ pub_path_ = nh.advertise<nav_msgs::Path>("/path", 100000);
|
|
|
+}
|
|
|
+
|
|
|
+Map_node::Map_node() {
|
|
|
+ preprocess_.reset(new PointCloudPreprocess());
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void Map_node::Run() {
|
|
|
+
|
|
|
+ if (!mapper_.Run())
|
|
|
+ return;
|
|
|
+ // publish or save map pcd
|
|
|
+ if (run_in_offline_) {
|
|
|
+ if (pcd_save_en_) {
|
|
|
+ PublishFrameWorld();
|
|
|
+ }
|
|
|
+ if (path_save_en_) {
|
|
|
+ PublishPath(pub_path_);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (pub_odom_aft_mapped_) {
|
|
|
+ PublishOdometry(pub_odom_aft_mapped_);
|
|
|
+ }
|
|
|
+ if (path_pub_en_ || path_save_en_) {
|
|
|
+ PublishPath(pub_path_);
|
|
|
+ }
|
|
|
+ if (scan_pub_en_ || pcd_save_en_) {
|
|
|
+ PublishFrameWorld();
|
|
|
+ }
|
|
|
+ if (scan_pub_en_ && scan_body_pub_en_) {
|
|
|
+ PublishFrameBody(pub_laser_cloud_body_);
|
|
|
+ }
|
|
|
+ if (scan_pub_en_ && scan_effect_pub_en_) {
|
|
|
+ PublishFrameEffectWorld(pub_laser_cloud_effect_world_);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Debug variables
|
|
|
+ mapper_.frame_num_++;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void Map_node::StandardPCLCallBack(const sensor_msgs::PointCloud2::ConstPtr &msg) {
|
|
|
+ mapper_.mtx_buffer_.lock();
|
|
|
+ Timer::Evaluate(
|
|
|
+ [&, this]() {
|
|
|
+ mapper_.scan_count_++;
|
|
|
+ if (msg->header.stamp.toSec() < mapper_.last_timestamp_lidar_) {
|
|
|
+ LOG(ERROR) << "lidar loop back, clear buffer";
|
|
|
+ mapper_.lidar_buffer_.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ PointCloudType::Ptr ptr(new PointCloudType());
|
|
|
+ preprocess_->Process(msg, ptr);
|
|
|
+ mapper_.lidar_buffer_.push_back(ptr);
|
|
|
+ mapper_.time_buffer_.push_back(msg->header.stamp.toSec());
|
|
|
+ mapper_.last_timestamp_lidar_ = msg->header.stamp.toSec();
|
|
|
+ },
|
|
|
+ "Preprocess (Standard)");
|
|
|
+ mapper_.mtx_buffer_.unlock();
|
|
|
+}
|
|
|
+
|
|
|
+void Map_node::LivoxPCLCallBack(const livox_ros_driver::CustomMsg::ConstPtr &msg) {
|
|
|
+ mapper_.mtx_buffer_.lock();
|
|
|
+ Timer::Evaluate(
|
|
|
+ [&, this]() {
|
|
|
+ //scan_count_++;
|
|
|
+ if (msg->header.stamp.toSec() < mapper_.last_timestamp_lidar_) {
|
|
|
+ LOG(WARNING) << "lidar loop back, clear buffer";
|
|
|
+ mapper_.lidar_buffer_.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ mapper_.last_timestamp_lidar_ = msg->header.stamp.toSec();
|
|
|
+
|
|
|
+ if (!mapper_.time_sync_en_ && abs(mapper_.last_timestamp_imu_ - mapper_.last_timestamp_lidar_) > 10.0 && !mapper_.imu_buffer_.empty() &&
|
|
|
+ !mapper_.lidar_buffer_.empty()) {
|
|
|
+ LOG(INFO) << "IMU and LiDAR not Synced, IMU time: " << mapper_.last_timestamp_imu_
|
|
|
+ << ", lidar header time: " << mapper_.last_timestamp_lidar_;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mapper_.time_sync_en_ && !mapper_.timediff_set_flg_ && abs(mapper_.last_timestamp_lidar_ - mapper_.last_timestamp_imu_) > 1 &&
|
|
|
+ !mapper_.imu_buffer_.empty()) {
|
|
|
+ mapper_.timediff_set_flg_ = true;
|
|
|
+ mapper_.timediff_lidar_wrt_imu_ = mapper_.last_timestamp_lidar_ + 0.1 - mapper_.last_timestamp_imu_;
|
|
|
+ LOG(INFO) << "Self sync IMU and LiDAR, time diff is " << mapper_.timediff_lidar_wrt_imu_;
|
|
|
+ }
|
|
|
+
|
|
|
+ PointCloudType::Ptr ptr(new PointCloudType());
|
|
|
+ preprocess_->Process(msg, ptr);
|
|
|
+ mapper_.AddPointCloud(ptr,mapper_.last_timestamp_lidar_);
|
|
|
+ /*lidar_buffer_.emplace_back(ptr);
|
|
|
+ time_buffer_.emplace_back(last_timestamp_lidar_);*/
|
|
|
+ },
|
|
|
+ "Preprocess (Livox)");
|
|
|
+
|
|
|
+ mapper_.mtx_buffer_.unlock();
|
|
|
+}
|
|
|
+
|
|
|
+void Map_node::IMUCallBack(const sensor_msgs::Imu::ConstPtr &msg_in) {
|
|
|
+ //publish_count_++;
|
|
|
+ sensor_msgs::Imu::Ptr msg(new sensor_msgs::Imu(*msg_in));
|
|
|
+
|
|
|
+ if (abs(mapper_.timediff_lidar_wrt_imu_) > 0.1 && mapper_.time_sync_en_) {
|
|
|
+ msg->header.stamp = ros::Time().fromSec(mapper_.timediff_lidar_wrt_imu_ + msg_in->header.stamp.toSec());
|
|
|
+ }
|
|
|
+
|
|
|
+ double timestamp = msg->header.stamp.toSec();
|
|
|
+
|
|
|
+
|
|
|
+ common::ImuData imu;
|
|
|
+ imu.timebase=msg_in->header.stamp.toSec();
|
|
|
+ imu.orientation=Eigen::Quaterniond(msg_in->orientation.w,msg_in->orientation.x,
|
|
|
+ msg_in->orientation.y,msg_in->orientation.z);
|
|
|
+ imu.orientation_covariance=Eigen::Matrix3d(msg_in->orientation_covariance.data());
|
|
|
+ imu.angular_velocity=Eigen::Vector3d(msg_in->angular_velocity.x,msg_in->angular_velocity.y,msg_in->angular_velocity.z);
|
|
|
+ imu.angular_velocity_covariance=Eigen::Matrix3d(msg_in->angular_velocity_covariance.data());
|
|
|
+ imu.linear_acceleration=Eigen::Vector3d(msg_in->linear_acceleration.x,msg_in->linear_acceleration.y,msg_in->linear_acceleration.z);
|
|
|
+ imu.linear_acceleration_covariance=Eigen::Matrix3d(msg_in->linear_acceleration_covariance.data());
|
|
|
+ mapper_.mtx_buffer_.lock();
|
|
|
+ mapper_.AddImu(imu,timestamp);
|
|
|
+ mapper_.mtx_buffer_.unlock();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+///////////////////////////////////// debug save / show /////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void Map_node::PublishPath(const ros::Publisher pub_path) {
|
|
|
+ SetPosestamp(msg_body_pose_);
|
|
|
+ msg_body_pose_.header.stamp = ros::Time().fromSec(mapper_.lidar_end_time_);
|
|
|
+ msg_body_pose_.header.frame_id = "camera_init";
|
|
|
+
|
|
|
+ /*** if path is too large, the rvis will crash ***/
|
|
|
+ path_.poses.push_back(msg_body_pose_);
|
|
|
+ if (run_in_offline_ == false) {
|
|
|
+ pub_path.publish(path_);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void Map_node::PublishOdometry(const ros::Publisher &pub_odom_aft_mapped) {
|
|
|
+ odom_aft_mapped_.header.frame_id = "camera_init";
|
|
|
+ odom_aft_mapped_.child_frame_id = "body";
|
|
|
+ odom_aft_mapped_.header.stamp = ros::Time().fromSec(mapper_.lidar_end_time_); // ros::Time().fromSec(lidar_end_time_);
|
|
|
+ SetPosestamp(odom_aft_mapped_.pose);
|
|
|
+ pub_odom_aft_mapped.publish(odom_aft_mapped_);
|
|
|
+ auto P = mapper_.kf_.get_P();
|
|
|
+ for (int i = 0; i < 6; i++) {
|
|
|
+ int k = i < 3 ? i + 3 : i - 3;
|
|
|
+ odom_aft_mapped_.pose.covariance[i * 6 + 0] = P(k, 3);
|
|
|
+ odom_aft_mapped_.pose.covariance[i * 6 + 1] = P(k, 4);
|
|
|
+ odom_aft_mapped_.pose.covariance[i * 6 + 2] = P(k, 5);
|
|
|
+ odom_aft_mapped_.pose.covariance[i * 6 + 3] = P(k, 0);
|
|
|
+ odom_aft_mapped_.pose.covariance[i * 6 + 4] = P(k, 1);
|
|
|
+ odom_aft_mapped_.pose.covariance[i * 6 + 5] = P(k, 2);
|
|
|
+ }
|
|
|
+
|
|
|
+ static tf::TransformBroadcaster br;
|
|
|
+ tf::Transform transform;
|
|
|
+ tf::Quaternion q;
|
|
|
+ transform.setOrigin(tf::Vector3(odom_aft_mapped_.pose.pose.position.x, odom_aft_mapped_.pose.pose.position.y,
|
|
|
+ odom_aft_mapped_.pose.pose.position.z));
|
|
|
+ q.setW(odom_aft_mapped_.pose.pose.orientation.w);
|
|
|
+ q.setX(odom_aft_mapped_.pose.pose.orientation.x);
|
|
|
+ q.setY(odom_aft_mapped_.pose.pose.orientation.y);
|
|
|
+ q.setZ(odom_aft_mapped_.pose.pose.orientation.z);
|
|
|
+ transform.setRotation(q);
|
|
|
+ br.sendTransform(tf::StampedTransform(transform, odom_aft_mapped_.header.stamp, "camera_init", "body"));
|
|
|
+}
|
|
|
+
|
|
|
+void Map_node::PublishFrameWorld() {
|
|
|
+ if (!(run_in_offline_ == false && scan_pub_en_) && !pcd_save_en_) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ PointCloudType::Ptr laserCloudWorld;
|
|
|
+ if (dense_pub_en_) {
|
|
|
+ PointCloudType::Ptr laserCloudFullRes(mapper_.scan_undistort_);
|
|
|
+ int size = laserCloudFullRes->points.size();
|
|
|
+ laserCloudWorld.reset(new PointCloudType(size, 1));
|
|
|
+ for (int i = 0; i < size; i++) {
|
|
|
+ mapper_.PointBodyToWorld(&laserCloudFullRes->points[i], &laserCloudWorld->points[i]);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ laserCloudWorld = mapper_.scan_down_world_;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (run_in_offline_ == false && scan_pub_en_) {
|
|
|
+ sensor_msgs::PointCloud2 laserCloudmsg;
|
|
|
+ pcl::toROSMsg(*laserCloudWorld, laserCloudmsg);
|
|
|
+ laserCloudmsg.header.stamp = ros::Time().fromSec(mapper_.lidar_end_time_);
|
|
|
+ laserCloudmsg.header.frame_id = "camera_init";
|
|
|
+ pub_laser_cloud_world_.publish(laserCloudmsg);
|
|
|
+ mapper_.publish_count_ -= options::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_) {
|
|
|
+ *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_) {
|
|
|
+ mapper_.pcd_index_++;
|
|
|
+ std::string all_points_dir(std::string(std::string(ROOT_DIR) + "PCD/scans_") + std::to_string(mapper_.pcd_index_) +
|
|
|
+ std::string(".pcd"));
|
|
|
+ pcl::PCDWriter pcd_writer;
|
|
|
+ LOG(INFO) << "current scan saved to /PCD/" << all_points_dir;
|
|
|
+ pcd_writer.writeBinary(all_points_dir, *pcl_wait_save_);
|
|
|
+ pcl_wait_save_->clear();
|
|
|
+ scan_wait_num = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void Map_node::PublishFrameBody(const ros::Publisher &pub_laser_cloud_body) {
|
|
|
+ int size = mapper_.scan_undistort_->points.size();
|
|
|
+ PointCloudType::Ptr laser_cloud_imu_body(new PointCloudType(size, 1));
|
|
|
+
|
|
|
+ for (int i = 0; i < size; i++) {
|
|
|
+ PointBodyLidarToIMU(&mapper_.scan_undistort_->points[i], &laser_cloud_imu_body->points[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ sensor_msgs::PointCloud2 laserCloudmsg;
|
|
|
+ pcl::toROSMsg(*laser_cloud_imu_body, laserCloudmsg);
|
|
|
+ laserCloudmsg.header.stamp = ros::Time().fromSec(mapper_.lidar_end_time_);
|
|
|
+ laserCloudmsg.header.frame_id = "body";
|
|
|
+ pub_laser_cloud_body.publish(laserCloudmsg);
|
|
|
+ mapper_.publish_count_ -= options::PUBFRAME_PERIOD;
|
|
|
+}
|
|
|
+
|
|
|
+void Map_node::PublishFrameEffectWorld(const ros::Publisher &pub_laser_cloud_effect_world) {
|
|
|
+ int size = mapper_.corr_pts_.size();
|
|
|
+ PointCloudType::Ptr laser_cloud(new PointCloudType(size, 1));
|
|
|
+
|
|
|
+ for (int i = 0; i < size; i++) {
|
|
|
+ mapper_.PointBodyToWorld(mapper_.corr_pts_[i].head<3>(), &laser_cloud->points[i]);
|
|
|
+ }
|
|
|
+ sensor_msgs::PointCloud2 laserCloudmsg;
|
|
|
+ pcl::toROSMsg(*laser_cloud, laserCloudmsg);
|
|
|
+ laserCloudmsg.header.stamp = ros::Time().fromSec(mapper_.lidar_end_time_);
|
|
|
+ laserCloudmsg.header.frame_id = "camera_init";
|
|
|
+ pub_laser_cloud_effect_world.publish(laserCloudmsg);
|
|
|
+ mapper_.publish_count_ -= options::PUBFRAME_PERIOD;
|
|
|
+}
|
|
|
+
|
|
|
+void Map_node::Savetrajectory(const std::string &traj_file) {
|
|
|
+ std::ofstream ofs;
|
|
|
+ ofs.open(traj_file, std::ios::out);
|
|
|
+ if (!ofs.is_open()) {
|
|
|
+ LOG(ERROR) << "Failed to open traj_file: " << traj_file;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ofs << "#timestamp x y z q_x q_y q_z q_w" << std::endl;
|
|
|
+ for (const auto &p : path_.poses) {
|
|
|
+ ofs << std::fixed << std::setprecision(6) << p.header.stamp.toSec() << " " << std::setprecision(15)
|
|
|
+ << p.pose.position.x << " " << p.pose.position.y << " " << p.pose.position.z << " " << p.pose.orientation.x
|
|
|
+ << " " << p.pose.orientation.y << " " << p.pose.orientation.z << " " << p.pose.orientation.w << std::endl;
|
|
|
+ }
|
|
|
+
|
|
|
+ ofs.close();
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////// private method /////////////////////////////////////////////////////////////////////
|
|
|
+template <typename T>
|
|
|
+void Map_node::SetPosestamp(T &out) {
|
|
|
+ out.pose.position.x = mapper_.state_point_.pos(0);
|
|
|
+ out.pose.position.y = mapper_.state_point_.pos(1);
|
|
|
+ out.pose.position.z = mapper_.state_point_.pos(2);
|
|
|
+ out.pose.orientation.x = mapper_.state_point_.rot.coeffs()[0];
|
|
|
+ out.pose.orientation.y = mapper_.state_point_.rot.coeffs()[1];
|
|
|
+ out.pose.orientation.z = mapper_.state_point_.rot.coeffs()[2];
|
|
|
+ out.pose.orientation.w = mapper_.state_point_.rot.coeffs()[3];
|
|
|
+}
|
|
|
+
|
|
|
+void Map_node::PointBodyLidarToIMU(PointType const *const pi, PointType *const po) {
|
|
|
+ common::V3D p_body_lidar(pi->x, pi->y, pi->z);
|
|
|
+ common::V3D p_body_imu(mapper_.state_point_.offset_R_L_I * p_body_lidar + mapper_.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 Map_node::Finish() {
|
|
|
+ /**************** 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_) {
|
|
|
+ std::string file_name = std::string("scans.pcd");
|
|
|
+ std::string all_points_dir(std::string(std::string(ROOT_DIR) + "PCD/") + file_name);
|
|
|
+ pcl::PCDWriter pcd_writer;
|
|
|
+ LOG(INFO) << "current scan saved to /PCD/" << file_name;
|
|
|
+ pcd_writer.writeBinary(all_points_dir, *pcl_wait_save_);
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG(INFO) << "finish done";
|
|
|
+}
|
|
|
+
|
|
|
+} // namespace faster_lio
|