#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /// *************Preconfiguration #define MAX_INI_COUNT (50) const bool time_list(PointType &x, PointType &y) {return (x.curvature < y.curvature);}; /// *************IMU Process and undistortion class ImuProcess { public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW ImuProcess(); ~ImuProcess(); void Process(const MeasureGroup &meas, StatesGroup &state, PointCloudXYZI::Ptr pcl_un_); void Reset(); void IMU_Initial(const MeasureGroup &meas, StatesGroup &state, int &N); // Eigen::Matrix3d Exp(const Eigen::Vector3d &ang_vel, const double &dt); void IntegrateGyr(const std::vector &v_imu); void UndistortPcl(const MeasureGroup &meas, StatesGroup &state_inout, PointCloudXYZI &pcl_in_out); ros::NodeHandle nh; void Integrate(const sensor_msgs::ImuConstPtr &imu); void Reset(double start_timestamp, const sensor_msgs::ImuConstPtr &lastimu); double scale_gravity; Eigen::Vector3d angvel_last; Eigen::Vector3d acc_s_last; Eigen::Matrix cov_proc_noise; Eigen::Vector3d cov_acc; Eigen::Vector3d cov_gyr; std::ofstream fout; private: /*** Whether is the first frame, init for first frame ***/ bool b_first_frame_ = true; bool imu_need_init_ = true; int init_iter_num = 1; Eigen::Vector3d mean_acc; Eigen::Vector3d mean_gyr; /*** Undistorted pointcloud ***/ PointCloudXYZI::Ptr cur_pcl_un_; //// For timestamp usage sensor_msgs::ImuConstPtr last_imu_; /*** For gyroscope integration ***/ double start_timestamp_; /// Making sure the equal size: v_imu_ and v_rot_ std::deque v_imu_; std::vector v_rot_pcl_; std::vector IMUpose; }; ImuProcess::ImuProcess() : b_first_frame_(true), imu_need_init_(true), last_imu_(nullptr), start_timestamp_(-1) { Eigen::Quaterniond q(0, 1, 0, 0); Eigen::Vector3d t(0, 0, 0); init_iter_num = 1; scale_gravity = 1.0; cov_acc = Eigen::Vector3d(0.1, 0.1, 0.1); cov_gyr = Eigen::Vector3d(0.1, 0.1, 0.1); mean_acc = Eigen::Vector3d(0, 0, -1.0); mean_gyr = Eigen::Vector3d(0, 0, 0); angvel_last = Zero3d; cov_proc_noise = Eigen::Matrix::Zero(); // Lidar_offset_to_IMU = Eigen::Vector3d(0.0, 0.0, -0.0); // fout.open(DEBUG_FILE_DIR("imu.txt"),std::ios::out); } ImuProcess::~ImuProcess() {fout.close();} void ImuProcess::Reset() { ROS_WARN("Reset ImuProcess"); scale_gravity = 1.0; angvel_last = Zero3d; cov_proc_noise = Eigen::Matrix::Zero(); cov_acc = Eigen::Vector3d(0.1, 0.1, 0.1); cov_gyr = Eigen::Vector3d(0.1, 0.1, 0.1); mean_acc = Eigen::Vector3d(0, 0, -1.0); mean_gyr = Eigen::Vector3d(0, 0, 0); imu_need_init_ = true; b_first_frame_ = true; init_iter_num = 1; last_imu_ = nullptr; //gyr_int_.Reset(-1, nullptr); start_timestamp_ = -1; v_imu_.clear(); IMUpose.clear(); cur_pcl_un_.reset(new PointCloudXYZI()); fout.close(); } void ImuProcess::IMU_Initial(const MeasureGroup &meas, StatesGroup &state_inout, int &N) { /** 1. initializing the gravity, gyro bias, acc and gyro covariance ** 2. normalize the acceleration measurenments to unit gravity **/ ROS_INFO("IMU Initializing: %.1f %%", double(N) / MAX_INI_COUNT * 100); Eigen::Vector3d cur_acc, cur_gyr; if (b_first_frame_) { Reset(); N = 1; b_first_frame_ = false; } for (const auto &imu : meas.imu) { const auto &imu_acc = imu->linear_acceleration; const auto &gyr_acc = imu->angular_velocity; cur_acc << imu_acc.x, imu_acc.y, imu_acc.z; cur_gyr << gyr_acc.x, gyr_acc.y, gyr_acc.z; scale_gravity += (cur_acc.norm() - scale_gravity) / N; mean_acc += (cur_acc - mean_acc) / N; mean_gyr += (cur_gyr - mean_gyr) / N; cov_acc = cov_acc * (N - 1.0) / N + (cur_acc - mean_acc).cwiseProduct(cur_acc - mean_acc) * (N - 1.0) / (N * N); cov_gyr = cov_gyr * (N - 1.0) / N + (cur_gyr - mean_gyr).cwiseProduct(cur_gyr - mean_gyr) * (N - 1.0) / (N * N); N ++; } state_inout.gravity = - mean_acc /scale_gravity * G_m_s2; state_inout.rot_end = Eye3d; // Exp(mean_acc.cross(Eigen::Vector3d(0, 0, -1 / scale_gravity))); state_inout.bias_g = mean_gyr; } void ImuProcess::UndistortPcl(const MeasureGroup &meas, StatesGroup &state_inout, PointCloudXYZI &pcl_out) { /*** add the imu of the last frame-tail to the of current frame-head ***/ auto v_imu = meas.imu; v_imu.push_front(last_imu_); const double &imu_beg_time = v_imu.front()->header.stamp.toSec(); const double &imu_end_time = v_imu.back()->header.stamp.toSec(); const double &pcl_beg_time = meas.lidar_beg_time; /*** sort point clouds by offset time ***/ pcl_out = *(meas.lidar); std::sort(pcl_out.points.begin(), pcl_out.points.end(), time_list); const double &pcl_end_time = pcl_beg_time + pcl_out.points.back().curvature / double(1000); std::cout<<"[ IMU Process ]: Process lidar from "<::Identity()); Eigen::MatrixXd cov_w(Eigen::Matrix::Zero()); double dt = 0; for (auto it_imu = v_imu.begin(); it_imu != (v_imu.end() - 1); it_imu++) { auto &&head = *(it_imu); auto &&tail = *(it_imu + 1); angvel_avr<<0.5 * (head->angular_velocity.x + tail->angular_velocity.x), 0.5 * (head->angular_velocity.y + tail->angular_velocity.y), 0.5 * (head->angular_velocity.z + tail->angular_velocity.z); acc_avr <<0.5 * (head->linear_acceleration.x + tail->linear_acceleration.x), 0.5 * (head->linear_acceleration.y + tail->linear_acceleration.y), 0.5 * (head->linear_acceleration.z + tail->linear_acceleration.z); angvel_avr -= state_inout.bias_g; acc_avr = acc_avr * G_m_s2 / scale_gravity - state_inout.bias_a; #ifdef DEBUG_PRINT // fout<header.stamp.toSec()<<" "<header.stamp.toSec() - head->header.stamp.toSec(); /* covariance propagation */ Eigen::Matrix3d acc_avr_skew; Eigen::Matrix3d Exp_f = Exp(angvel_avr, dt); acc_avr_skew<(0,0) = - Exp_f; F_x.block<3,3>(0,9) = - Eye3d * dt; // F_x.block<3,3>(3,0) = R_imu * off_vel_skew * dt; F_x.block<3,3>(3,6) = Eye3d * dt; F_x.block<3,3>(6,0) = - R_imu * acc_avr_skew * dt; F_x.block<3,3>(6,12) = - R_imu * dt; F_x.block<3,3>(6,15) = Eye3d * dt; Eigen::Matrix3d cov_acc_diag(Eye3d), cov_gyr_diag(Eye3d); cov_acc_diag.diagonal() = cov_acc; cov_gyr_diag.diagonal() = cov_gyr; cov_w.block<3,3>(0,0).diagonal() = cov_gyr * dt * dt * 10000; cov_w.block<3,3>(3,3) = R_imu * cov_gyr_diag * R_imu.transpose() * dt * dt * 10000; cov_w.block<3,3>(6,6) = R_imu * cov_acc_diag * R_imu.transpose() * dt * dt * 10000; cov_w.block<3,3>(9,9).diagonal() = Eigen::Vector3d(0.0001, 0.0001, 0.0001) * dt * dt; // bias gyro covariance cov_w.block<3,3>(12,12).diagonal() = Eigen::Vector3d(0.0001, 0.0001, 0.0001) * dt * dt; // bias acc covariance state_inout.cov = F_x * state_inout.cov * F_x.transpose() + cov_w; /* propogation of IMU attitude */ R_imu = R_imu * Exp_f; /* Specific acceleration (global frame) of IMU */ acc_imu = R_imu * acc_avr + state_inout.gravity; /* propogation of IMU */ pos_imu = pos_imu + vel_imu * dt + 0.5 * acc_imu * dt * dt; /* velocity of IMU */ vel_imu = vel_imu + acc_imu * dt; /* save the poses at each IMU measurements */ angvel_last = angvel_avr; acc_s_last = acc_imu; double &&offs_t = tail->header.stamp.toSec() - pcl_beg_time; // std::cout<<"acc "<rot); acc_imu<acc); // std::cout<<"head imu acc: "<vel); pos_imu<pos); angvel_avr<gyr); int i = 0; for(; it_pcl->curvature / double(1000) > head->offset_time; it_pcl --) { dt = it_pcl->curvature / double(1000) - head->offset_time; /* Transform to the 'end' frame, using only the rotation * Note: Compensation direction is INVERSE of Frame's moving direction * So if we want to compensate a point at timestamp-i to the frame-e * P_compensate = R_imu_e ^ T * (R_i * P_i + T_ei) where T_ei is represented in global frame */ Eigen::Matrix3d R_i(R_imu * Exp(angvel_avr, dt)); Eigen::Vector3d T_ei(pos_imu + vel_imu * dt + 0.5 * acc_imu * dt * dt + R_i * Lidar_offset_to_IMU - pos_liD_e); Eigen::Vector3d P_i(it_pcl->x, it_pcl->y, it_pcl->z); Eigen::Vector3d P_compensate = state_inout.rot_end.transpose() * (R_i * P_i + T_ei); /// save Undistorted points and their rotation it_pcl->x = P_compensate(0); it_pcl->y = P_compensate(1); it_pcl->z = P_compensate(2); if (it_pcl == pcl_out.points.begin()) break; } } } void ImuProcess::Process(const MeasureGroup &meas, StatesGroup &stat, PointCloudXYZI::Ptr cur_pcl_un_) { double t1,t2,t3; t1 = omp_get_wtime(); if(meas.imu.empty()) {std::cout<<"no imu data"< MAX_INI_COUNT) { imu_need_init_ = false; // std::cout<<"mean acc: "<("/livox_undistort", 100); // sensor_msgs::PointCloud2 pcl_out_msg; // pcl::toROSMsg(*cur_pcl_un_, pcl_out_msg); // pcl_out_msg.header.stamp = ros::Time().fromSec(meas.lidar_beg_time); // pcl_out_msg.header.frame_id = "/livox"; // pub_UndistortPcl.publish(pcl_out_msg); // } /// Record last measurements last_imu_ = meas.imu.back(); t3 = omp_get_wtime(); std::cout<<"[ IMU Process ]: Time: "<