VIR-SLAM代码分析3——VIR_VINS详解之estimator.cpp/.h
前言
续接上一篇,本本篇接着介绍VIR-SLAM中estimator.cpp/.h文件的函数,尤其是和UWB相关的相比于VINS改动过的函数,仍然以具体功能情况+代码注释的形式进行介绍。
重点函数介绍
优化函数,代码是先优化,后边缘化。
void Estimator::optimization()
{ceres::Problem problem;ceres::LossFunction *loss_function;//loss_function = new ceres::HuberLoss(1.0);loss_function = new ceres::CauchyLoss(1.0);for (int i = 0; i < WINDOW_SIZE + 1; i++)//添加各种待优化量X——位姿优化量,还包括最新的第11帧{ceres::LocalParameterization *local_parameterization = new PoseLocalParameterization();problem.AddParameterBlock(para_Pose[i], SIZE_POSE, local_parameterization);problem.AddParameterBlock(para_SpeedBias[i], SIZE_SPEEDBIAS);}for (int i = 0; i < NUM_OF_CAM; i++)//7维、相机IMU外参{ceres::LocalParameterization *local_parameterization = new PoseLocalParameterization();problem.AddParameterBlock(para_Ex_Pose[i], SIZE_POSE, local_parameterization);if (!ESTIMATE_EXTRINSIC)//如果IMU-相机外参不需要标定{ROS_DEBUG("fix extinsic param");problem.SetParameterBlockConstant(para_Ex_Pose[i]);//这个变量固定为constant}elseROS_DEBUG("estimate extinsic param");}if (ESTIMATE_TD)//IMU-image时间同步误差,1维,标定同步时间{problem.AddParameterBlock(para_Td[0], 1);//problem.SetParameterBlockConstant(para_Td[0]);}TicToc t_whole, t_prepare;vector2double(); // 因为ceres用的是double数组,所以下面用vector2double做类型转换if (last_marginalization_info)//添加先验信残差{// construct new marginlization_factor, for the prior element.MarginalizationFactor *marginalization_factor = new MarginalizationFactor(last_marginalization_info);problem.AddResidualBlock(marginalization_factor, NULL,last_marginalization_parameter_blocks);}for (int i = 0; i < WINDOW_SIZE; i++)//添加IMU残差{int j = i + 1;if (pre_integrations[j]->sum_dt > 10.0)continue;IMUFactor* imu_factor = new IMUFactor(pre_integrations[j]);problem.AddResidualBlock(imu_factor, NULL, para_Pose[i], para_SpeedBias[i], para_Pose[j], para_SpeedBias[j]);}if(USE_UWB && PsLong.size() == (WINDOW_SIZE_LONG) && KNOWN_ANCHOR == 1)//添加UWB残差{ //add edge for long windowfor (int i = 0; i < PsLong.size(); i++){ceres::LocalParameterization *local_parameterization = new PoseLocalParameterization();problem.AddParameterBlock(para_Pose_Long[i], SIZE_POSE, local_parameterization);}for (int i = 1; i < PsLong.size(); i++){for (int j = 1; j < 5; j++){int neibLink = i-j;if (neibLink >0){//cout<<" Add residual in pslong "<< i << " "<< neibLink << " pslong size "<< PsLong.size() << " "<< endl;ceres::CostFunction* cost_function = LongWindowError::Create(PsLong.at(neibLink), PsLong.at(i), RsLong.at(neibLink), RsLong.at(i), LINK_W);problem.AddResidualBlock(cost_function, NULL, para_Pose_Long[neibLink], para_Pose_Long[i]);}}ceres::CostFunction* cost_function = movingError::Create(PsLong.at(i), MOVE_W);problem.AddResidualBlock(cost_function, NULL, para_Pose_Long[i]);}// //Link between pose in window and long windowfor (int i = 0; i < WINDOW_SIZE; i++){for (int j = 1; j <WINDOW_SIZE_LONG; j++){ unsigned neibLink = PsLong.size() + i-j;if (neibLink<PsLong.size()){ceres::CostFunction* cost_function = LongWindowError::Create( PsLong.at(neibLink),Ps[i], RsLong.at(neibLink), Rs[i], 1);problem.AddResidualBlock(cost_function, NULL, para_Pose_Long[neibLink], para_Pose[i]);}}}//cout<<" Opt with UWB uwb_keymeas size "<<uwb_keymeas.size()<<" ; "<< endl;double uwbResidual = 0;for (int i = WINDOW_SIZE+WINDOW_SIZE_LONG-1; i >=0; i--){//cout<<" For uwb meas i-1 "<< i <<" "<< uwb_keymeas.at(i) <<endl;if (uwb_keymeas.at(i)>1.5){double avgWindow = 4;std::deque<double> temp_keymeas = uwb_keymeas;for (int k = 0; k<avgWindow/2; k++){temp_keymeas.push_front(uwb_keymeas.front());temp_keymeas.push_back(uwb_keymeas.back());}int posID = i - WINDOW_SIZE_LONG; if (posID >= 0){auto st = temp_keymeas.begin()+ i ;auto ed = temp_keymeas.begin()+ i + avgWindow;double sum = 0;int nums = 0;for( auto iit = st; iit < ed; iit ++){if (*iit != -1){sum+= *iit;nums ++;}}double average = sum/nums;//cout<<"avg start "<<*st << " end "<< *ed << " sum "<< sum << " "<< nums << endl;//double average = std::accumulate(st, ed, 0.0) / avgWindow;// //double res = Ps[posID].norm()-uwb_keymeas.at(i);//cout<<" Short window "<< i <<" "<< uwb_keymeas.at(i) << " avg "<< average<<" ; pos " << posID << " (" << para_Pose[posID][0]<<" " << para_Pose[posID][1]<<" " << para_Pose[posID][2]<< " ); " <<endl;UWBFactor* uwb_factor = new UWBFactor(average,RANGE_W);//UWBFactor* uwb_factor = new UWBFactor(uwb_keymeas.at(i),RANGE_W);// //ceres::LossFunction *loss_function;// //loss_function = new ceres::HuberLoss(2);problem.AddResidualBlock(uwb_factor, NULL, para_Pose[posID], anchor_pos); double res = Ps[posID].norm()-average;uwbResidual+=abs(res);}else{int idx_in_long = i;auto st = temp_keymeas.begin()+ i ;auto ed = temp_keymeas.begin()+ i + avgWindow;double sum = 0;int nums = 0;for( auto iit = st; iit < ed; iit ++){if (*iit != -1){sum+= *iit;nums ++;}}double average = sum/nums;/*** Block following module to test algorithm without long window optimization ***/// if ((idx_in_long%1)==0)// {// //double res = PsLong[idx_in_long].norm()-uwb_keymeas.at(i);// double res = PsLong[idx_in_long].norm()-average;// //cout<<" Long window " << i <<" "<< uwb_keymeas[i]<< " avg " << average <<" ; pos ("<< idx_in_long << " " << para_Pose_Long[idx_in_long][0]<<" " << para_Pose_Long[idx_in_long][1]<<" " << para_Pose_Long[idx_in_long][2]<< " ); " <<endl;// UWBFactor* uwb_factor = new UWBFactor(average, RANGE_W);// //UWBFactor* uwb_factor = new UWBFactor(uwb_keymeas.at(i), RANGE_W);// //ceres::LossFunction *loss_function;// //loss_function = new ceres::CauchyLoss(1.0) ;//new ceres::HuberLoss(0.1);// problem.AddResidualBlock(uwb_factor, NULL, para_Pose_Long[idx_in_long], anchor_pos); // uwbResidual+=abs(res);// }}}}//cout<<">>>>>>Before optimization: Total uwb residuals "<< uwbResidual <<" anchor pos "<< anchor_pos[0] <<" "<< anchor_pos[1] <<" "<< anchor_pos[2] <<" ;"<<endl; }//添加视觉残差int f_m_cnt = 0;int feature_index = -1;for (auto &it_per_id : f_manager.feature)//feature是滑动窗口内所有的特征点的集合{it_per_id.used_num = it_per_id.feature_per_frame.size();if (!(it_per_id.used_num >= 2 && it_per_id.start_frame < WINDOW_SIZE - 2)) // 如果这个特征点被观测的次数大于等于2 并且首次观测到该特征点的帧小于滑动窗口倒数第3帧,这个特征点就可以建立一个残差continue;++feature_index;int imu_i = it_per_id.start_frame, imu_j = imu_i - 1;//得到观测到该特征点的首帧Vector3d pts_i = it_per_id.feature_per_frame[0].point;//得到首帧观测到的特征点的归一化相机坐标for (auto &it_per_frame : it_per_id.feature_per_frame){imu_j++;if (imu_i == imu_j){continue;}Vector3d pts_j = it_per_frame.point;//得到第二个特征点if (ESTIMATE_TD){ProjectionTdFactor *f_td = new ProjectionTdFactor(pts_i, pts_j, it_per_id.feature_per_frame[0].velocity, it_per_frame.velocity,it_per_id.feature_per_frame[0].cur_td, it_per_frame.cur_td,it_per_id.feature_per_frame[0].uv.y(), it_per_frame.uv.y());problem.AddResidualBlock(f_td, loss_function, para_Pose[imu_i], para_Pose[imu_j], para_Ex_Pose[0], para_Feature[feature_index], para_Td[0]);/*double **para = new double *[5];para[0] = para_Pose[imu_i];para[1] = para_Pose[imu_j];para[2] = para_Ex_Pose[0];para[3] = para_Feature[feature_index];para[4] = para_Td[0];f_td->check(para);*/}else{ProjectionFactor *f = new ProjectionFactor(pts_i, pts_j);problem.AddResidualBlock(f, loss_function, para_Pose[imu_i], para_Pose[imu_j], para_Ex_Pose[0], para_Feature[feature_index]);}f_m_cnt++;}}ROS_DEBUG("visual measurement count: %d", f_m_cnt);ROS_DEBUG("prepare for ceres: %f", t_prepare.toc());if(relocalization_info){//printf("set relocalization factor! \n");ceres::LocalParameterization *local_parameterization = new PoseLocalParameterization();problem.AddParameterBlock(relo_Pose, SIZE_POSE, local_parameterization);int retrive_feature_index = 0;int feature_index = -1;for (auto &it_per_id : f_manager.feature){it_per_id.used_num = it_per_id.feature_per_frame.size();if (!(it_per_id.used_num >= 2 && it_per_id.start_frame < WINDOW_SIZE - 2))continue;++feature_index;int start = it_per_id.start_frame;if(start <= relo_frame_local_index){ while((int)match_points[retrive_feature_index].z() < it_per_id.feature_id){retrive_feature_index++;}if((int)match_points[retrive_feature_index].z() == it_per_id.feature_id){Vector3d pts_j = Vector3d(match_points[retrive_feature_index].x(), match_points[retrive_feature_index].y(), 1.0);Vector3d pts_i = it_per_id.feature_per_frame[0].point;ProjectionFactor *f = new ProjectionFactor(pts_i, pts_j);problem.AddResidualBlock(f, loss_function, para_Pose[start], relo_Pose, para_Ex_Pose[0], para_Feature[feature_index]);retrive_feature_index++;} }}}ceres::Solver::Options options;//设置求解器options.linear_solver_type = ceres::DENSE_SCHUR;//options.num_threads = 2;options.trust_region_strategy_type = ceres::DOGLEG;options.max_num_iterations = NUM_ITERATIONS;//options.use_explicit_schur_complement = true;//options.minimizer_progress_to_stdout = true;//options.use_nonmonotonic_steps = true;if (marginalization_flag == MARGIN_OLD)options.max_solver_time_in_seconds = SOLVER_TIME * 4.0 / 5.0;elseoptions.max_solver_time_in_seconds = SOLVER_TIME;TicToc t_solver;ceres::Solver::Summary summary;ceres::Solve(options, &problem, &summary);cout << summary.BriefReport() << endl;ROS_DEBUG("Iterations : %d", static_cast<int>(summary.iterations.size()));ROS_DEBUG("solver costs: %f", t_solver.toc());double2vector();// calculate the residual of all uwb measurementsif ( USE_UWB && PsLong.size() == (WINDOW_SIZE_LONG)){double uwbResidual = 0;for (int i = WINDOW_SIZE+WINDOW_SIZE_LONG-1; i >=0; i--){//cout<<" For uwb meas i-1 "<< i <<" "<< uwb_keymeas.at(i) <<endl;if (uwb_keymeas.at(i)>1.5){int posID = i - WINDOW_SIZE_LONG; if (posID >= 0){double res = Ps[posID].norm()-uwb_keymeas.at(i);uwbResidual+=abs(res);}else{int idx_in_long = i;if ((idx_in_long%1)==0){double res = PsLong_result[idx_in_long].norm()-uwb_keymeas.at(i);uwbResidual+=abs(res);}}}}//cout<<"after optimization: Total uwb residuals "<< uwbResidual <<" anchor pos "<< anchor_pos[0] <<" "<< anchor_pos[1] <<" "<< anchor_pos[2] <<" ;"<<endl; }//Step3:marg部分//1.把之前存的残差部分加进来//2.把与当前要marg掉的帧的所有相关残差项加进来,IMU,vision.//3.preMarginalize-> 调用Evaluate计算所有ResidualBlock的残差和雅克比,parameter_block_data是margniliazation中存参数块的容器//4.多线程构造Hx=b的结构,H是边缘化后的结果,First Estimate Jacobian,在X0处进行线性化,需要去看!!!!???????????????????????????//5.marg结束,调整参数块在下一次window中对应的位置TicToc t_whole_marginalization;if (marginalization_flag == MARGIN_OLD){MarginalizationInfo *marginalization_info = new MarginalizationInfo();vector2double();//! 先验误差会一直保存,而不是只使用一次//! 如果上一次边缘化的信息存在//! 要边缘化的参数块是 para_Pose[0] para_SpeedBias[0] 以及 para_Feature[feature_index](滑窗内的第feature_index个点的逆深度)if (last_marginalization_info){vector<int> drop_set;for (int i = 0; i < static_cast<int>(last_marginalization_parameter_blocks.size()); i++){// 查询last_marginalization_parameter_blocks中是首帧状态量的序号if (last_marginalization_parameter_blocks[i] == para_Pose[0] ||last_marginalization_parameter_blocks[i] == para_SpeedBias[0])drop_set.push_back(i);}// construct new marginlization_factor,//! 构造边缘化的的FactorMarginalizationFactor *marginalization_factor = new MarginalizationFactor(last_marginalization_info);//添加上一次边缘化的参数块ResidualBlockInfo *residual_block_info = new ResidualBlockInfo(marginalization_factor, NULL,last_marginalization_parameter_blocks,drop_set);marginalization_info->addResidualBlockInfo(residual_block_info);}{if (pre_integrations[1]->sum_dt < 10.0)//添加IMU的先验,只包含边缘化帧的IMU测量残差{IMUFactor* imu_factor = new IMUFactor(pre_integrations[1]);ResidualBlockInfo *residual_block_info = new ResidualBlockInfo(imu_factor, NULL,vector<double *>{para_Pose[0], para_SpeedBias[0], para_Pose[1], para_SpeedBias[1]},vector<int>{0, 1});marginalization_info->addResidualBlockInfo(residual_block_info);}}{//添加视觉的先验,只添加起始帧是旧帧且观测次数大于2的Featuresint feature_index = -1;for (auto &it_per_id : f_manager.feature)//遍历滑窗内所有的Features{it_per_id.used_num = it_per_id.feature_per_frame.size();//该特征点被观测到的次数if (!(it_per_id.used_num >= 2 && it_per_id.start_frame < WINDOW_SIZE - 2))//Feature的观测次数不小于2次,且起始帧不属于最后两帧continue;++feature_index;int imu_i = it_per_id.start_frame, imu_j = imu_i - 1;//只选择被边缘化的帧的Featuresif (imu_i != 0)continue;Vector3d pts_i = it_per_id.feature_per_frame[0].point;for (auto &it_per_frame : it_per_id.feature_per_frame){imu_j++;if (imu_i == imu_j)continue;Vector3d pts_j = it_per_frame.point;//得到该Feature在起始下的归一化坐标if (ESTIMATE_TD){ProjectionTdFactor *f_td = new ProjectionTdFactor(pts_i, pts_j, it_per_id.feature_per_frame[0].velocity, it_per_frame.velocity,it_per_id.feature_per_frame[0].cur_td, it_per_frame.cur_td,it_per_id.feature_per_frame[0].uv.y(), it_per_frame.uv.y());ResidualBlockInfo *residual_block_info = new ResidualBlockInfo(f_td, loss_function,vector<double *>{para_Pose[imu_i], para_Pose[imu_j], para_Ex_Pose[0], para_Feature[feature_index], para_Td[0]},vector<int>{0, 3});marginalization_info->addResidualBlockInfo(residual_block_info);}else{ProjectionFactor *f = new ProjectionFactor(pts_i, pts_j);ResidualBlockInfo *residual_block_info = new ResidualBlockInfo(f, loss_function,vector<double *>{para_Pose[imu_i], para_Pose[imu_j], para_Ex_Pose[0], para_Feature[feature_index]},vector<int>{0, 3});marginalization_info->addResidualBlockInfo(residual_block_info);}}}}//将三个ResidualBlockInfo中的参数块综合到marginalization_info中// 计算所有ResidualBlock(残差项)的残差和雅克比,parameter_block_data是参数块的容器TicToc t_pre_margin;marginalization_info->preMarginalize();ROS_DEBUG("pre marginalization %f ms", t_pre_margin.toc());TicToc t_margin;marginalization_info->marginalize();ROS_DEBUG("marginalization %f ms", t_margin.toc());std::unordered_map<long, double *> addr_shift;for (int i = 1; i <= WINDOW_SIZE; i++){addr_shift[reinterpret_cast<long>(para_Pose[i])] = para_Pose[i - 1];addr_shift[reinterpret_cast<long>(para_SpeedBias[i])] = para_SpeedBias[i - 1];}for (int i = 0; i < NUM_OF_CAM; i++)addr_shift[reinterpret_cast<long>(para_Ex_Pose[i])] = para_Ex_Pose[i];if (ESTIMATE_TD){addr_shift[reinterpret_cast<long>(para_Td[0])] = para_Td[0];}vector<double *> parameter_blocks = marginalization_info->getParameterBlocks(addr_shift);if (last_marginalization_info)delete last_marginalization_info;last_marginalization_info = marginalization_info;last_marginalization_parameter_blocks = parameter_blocks;}else //MARGIN_SECOND_NEW边缘化倒数第二帧//如果倒数第二帧不是关键帧//1.保留该帧的IMU测量,去掉该帧的visual,代码中都没有写.//2.premarg//3.marg//4.滑动窗口移动{if (last_marginalization_info &&std::count(std::begin(last_marginalization_parameter_blocks), std::end(last_marginalization_parameter_blocks), para_Pose[WINDOW_SIZE - 1])){MarginalizationInfo *marginalization_info = new MarginalizationInfo();vector2double();if (last_marginalization_info){vector<int> drop_set;for (int i = 0; i < static_cast<int>(last_marginalization_parameter_blocks.size()); i++){ROS_ASSERT(last_marginalization_parameter_blocks[i] != para_SpeedBias[WINDOW_SIZE - 1]);if (last_marginalization_parameter_blocks[i] == para_Pose[WINDOW_SIZE - 1])drop_set.push_back(i);}// construct new marginlization_factorMarginalizationFactor *marginalization_factor = new MarginalizationFactor(last_marginalization_info);ResidualBlockInfo *residual_block_info = new ResidualBlockInfo(marginalization_factor, NULL,last_marginalization_parameter_blocks,drop_set);marginalization_info->addResidualBlockInfo(residual_block_info);}TicToc t_pre_margin;ROS_DEBUG("begin marginalization");marginalization_info->preMarginalize();ROS_DEBUG("end pre marginalization, %f ms", t_pre_margin.toc());TicToc t_margin;ROS_DEBUG("begin marginalization");marginalization_info->marginalize();ROS_DEBUG("end marginalization, %f ms", t_margin.toc());std::unordered_map<long, double *> addr_shift;for (int i = 0; i <= WINDOW_SIZE; i++){if (i == WINDOW_SIZE - 1)continue;else if (i == WINDOW_SIZE){addr_shift[reinterpret_cast<long>(para_Pose[i])] = para_Pose[i - 1];addr_shift[reinterpret_cast<long>(para_SpeedBias[i])] = para_SpeedBias[i - 1];}else{addr_shift[reinterpret_cast<long>(para_Pose[i])] = para_Pose[i];addr_shift[reinterpret_cast<long>(para_SpeedBias[i])] = para_SpeedBias[i];}}for (int i = 0; i < NUM_OF_CAM; i++)addr_shift[reinterpret_cast<long>(para_Ex_Pose[i])] = para_Ex_Pose[i];if (ESTIMATE_TD){addr_shift[reinterpret_cast<long>(para_Td[0])] = para_Td[0];}vector<double *> parameter_blocks = marginalization_info->getParameterBlocks(addr_shift);if (last_marginalization_info)delete last_marginalization_info;last_marginalization_info = marginalization_info;last_marginalization_parameter_blocks = parameter_blocks;}}ROS_DEBUG("whole marginalization costs: %f", t_whole_marginalization.toc());ROS_DEBUG("whole time for ceres: %f", t_whole.toc());
}
滑动窗口函数
实际滑动窗口的地方,如果第二最新帧是关键帧的话,那么这个关键帧就会留在滑动窗口中,时间最长的一帧和其测量值就会被边缘化掉;如果第二最新帧不是关键帧的话,则把这帧的视觉测量舍弃掉而保留IMU测量值在滑动窗口中,这样的策略会保证系统的稀疏性。这一部分跟后端非线性优化是一起进行的,这一部分对应的非线性优化的损失函数的先验部分。
void Estimator::slideWindow()
{TicToc t_margin;if (marginalization_flag == MARGIN_OLD){double t_0 = Headers[0].stamp.toSec();back_R0 = Rs[0];back_P0 = Ps[0];if (frame_count == WINDOW_SIZE){ for (int i = 0; i < WINDOW_SIZE; i++) // Swap equals to remove the oldest one.{Rs[i].swap(Rs[i + 1]);std::swap(pre_integrations[i], pre_integrations[i + 1]);dt_buf[i].swap(dt_buf[i + 1]);linear_acceleration_buf[i].swap(linear_acceleration_buf[i + 1]);angular_velocity_buf[i].swap(angular_velocity_buf[i + 1]);Headers[i] = Headers[i + 1];Ps[i].swap(Ps[i + 1]);Vs[i].swap(Vs[i + 1]);Bas[i].swap(Bas[i + 1]);Bgs[i].swap(Bgs[i + 1]);}// Manually change the newest position as same as the real newest one.Headers[WINDOW_SIZE] = Headers[WINDOW_SIZE - 1];Ps[WINDOW_SIZE] = Ps[WINDOW_SIZE - 1];Vs[WINDOW_SIZE] = Vs[WINDOW_SIZE - 1];Rs[WINDOW_SIZE] = Rs[WINDOW_SIZE - 1];Bas[WINDOW_SIZE] = Bas[WINDOW_SIZE - 1];Bgs[WINDOW_SIZE] = Bgs[WINDOW_SIZE - 1];delete pre_integrations[WINDOW_SIZE];pre_integrations[WINDOW_SIZE] = new IntegrationBase{acc_0, gyr_0, Bas[WINDOW_SIZE], Bgs[WINDOW_SIZE]};dt_buf[WINDOW_SIZE].clear();linear_acceleration_buf[WINDOW_SIZE].clear();angular_velocity_buf[WINDOW_SIZE].clear();if (true || solver_flag == INITIAL){map<double, ImageFrame>::iterator it_0;it_0 = all_image_frame.find(t_0);delete it_0->second.pre_integration;it_0->second.pre_integration = nullptr;for (map<double, ImageFrame>::iterator it = all_image_frame.begin(); it != it_0; ++it){if (it->second.pre_integration)delete it->second.pre_integration;it->second.pre_integration = NULL;}all_image_frame.erase(all_image_frame.begin(), it_0);all_image_frame.erase(t_0);}slideWindowOld();}}else // MARGIN_NEW{if (frame_count == WINDOW_SIZE){for (unsigned int i = 0; i < dt_buf[WINDOW_SIZE].size(); i++){double tmp_dt = dt_buf[WINDOW_SIZE][i];Vector3d tmp_linear_acceleration = linear_acceleration_buf[WINDOW_SIZE][i];Vector3d tmp_angular_velocity = angular_velocity_buf[WINDOW_SIZE][i];pre_integrations[WINDOW_SIZE - 1]->push_back(tmp_dt, tmp_linear_acceleration, tmp_angular_velocity);dt_buf[WINDOW_SIZE - 1].push_back(tmp_dt);linear_acceleration_buf[WINDOW_SIZE - 1].push_back(tmp_linear_acceleration);angular_velocity_buf[WINDOW_SIZE - 1].push_back(tmp_angular_velocity);}Headers[WINDOW_SIZE - 1] = Headers[WINDOW_SIZE];Ps[WINDOW_SIZE - 1] = Ps[WINDOW_SIZE];Vs[WINDOW_SIZE - 1] = Vs[WINDOW_SIZE];Rs[WINDOW_SIZE - 1] = Rs[WINDOW_SIZE];Bas[WINDOW_SIZE - 1] = Bas[WINDOW_SIZE];Bgs[WINDOW_SIZE - 1] = Bgs[WINDOW_SIZE];delete pre_integrations[WINDOW_SIZE];pre_integrations[WINDOW_SIZE] = new IntegrationBase{acc_0, gyr_0, Bas[WINDOW_SIZE], Bgs[WINDOW_SIZE]};dt_buf[WINDOW_SIZE].clear();linear_acceleration_buf[WINDOW_SIZE].clear();angular_velocity_buf[WINDOW_SIZE].clear();slideWindowNew();}}
}// real marginalization is removed in optimization()
void Estimator::slideWindowNew()
{sum_of_front++;f_manager.removeFront(frame_count);if (USE_UWB){uwb_keymeas.pop_back();//printf("slide window new-> size of uwb_keymeas %d \n", uwb_keymeas.size()); if (KNOWN_ANCHOR == 0 && solver_flag == NON_LINEAR && uwbMeas4AnchorEst.size()>0){uwbMeas4AnchorEst.pop_back();}}
}
// real marginalization is removed in optimization()
void Estimator::slideWindowOld()
{sum_of_back++;bool shift_depth = solver_flag == NON_LINEAR ? true : false;if (shift_depth){Matrix3d R0, R1;Vector3d P0, P1;R0 = back_R0 * ric[0];R1 = Rs[0] * ric[0];P0 = back_P0 + back_R0 * tic[0];P1 = Ps[0] + Rs[0] * tic[0];f_manager.removeBackShiftDepth(R0, P0, R1, P1);}elsef_manager.removeBack();if (USE_UWB && uwb_keymeas.size() > WINDOW_SIZE_LONG+WINDOW_SIZE){uwb_keymeas.pop_front();}if (USE_UWB && solver_flag == NON_LINEAR){if (KNOWN_ANCHOR == 1){PsLong.push_back(back_P0);RsLong.push_back(back_R0);//printf(" slide window old-> size of uwb_keymeas %d \n", uwb_keymeas.size());if (PsLong.size() > (WINDOW_SIZE_LONG)){PsLong.pop_front();RsLong.pop_front();//cout<< "SlideWindow Old, cur first Pos"<< back_P0[0]<<" "<< back_P0[1]<<" "<< back_P0[2]<< " uwb meas front "<< uwb_keymeas.front() <<" uwb meas end "<< uwb_keymeas.back() <<" wubmeas size " << uwb_keymeas.size()<<" ;"<<endl;}}else if(KNOWN_ANCHOR == 0){pose4AnchorEst.push_back(Ps[WINDOW_SIZE - 1]);} }
}
锚点估计函数,同样在imageprocess函数中调用的。
void Estimator::estimateAnchorPos()
{if(USE_UWB && KNOWN_ANCHOR == 0 && pose4AnchorEst.size() > POS_SIZE_4_ANCHOR_EST && uwbMeas4AnchorEst.size()>POS_SIZE_4_ANCHOR_EST){cout<<"------------NOW can do Anchor Estimation pose size "<< pose4AnchorEst.size() <<"; uwb meas size "<< uwbMeas4AnchorEst.size()<<" ;"<<endl; ceres::Problem problem;ceres::Solver::Options options;options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;//options.minimizer_progress_to_stdout = true;options.max_solver_time_in_seconds = 3;options.max_num_iterations = 50*3;ceres::Solver::Summary summary;// Add residual blocks, which are uwb factors.double uwbResidual;for(int idx = POS_SIZE_4_ANCHOR_EST; idx>0; idx--){double temprange = uwbMeas4AnchorEst.back();Eigen::Vector3d tempPose(pose4AnchorEst.back()[0],pose4AnchorEst.back()[1],pose4AnchorEst.back()[2]);uwbMeas4AnchorEst.pop_back();pose4AnchorEst.pop_back();if (temprange>0.5){double res = tempPose.norm()-temprange;UWBAnchorFactor* anchor_factor = new UWBAnchorFactor(temprange, RANGE_W, tempPose);//ceres::LossFunction *loss_function//loss_function = new ceres::CauchyLoss(1.0) ;//new ceres::HuberLoss(0.1);problem.AddResidualBlock(anchor_factor, NULL, anchor_pos); uwbResidual+=abs(res);cout << "range " << temprange<<" pos ("<<tempPose[0]<<", "<< tempPose[1]<<", "<<tempPose[2]<<" )"<<endl;} }ceres::Solve(options, &problem, &summary);std::cout << summary.BriefReport()<< "\n";cout<< " Anchor "<< anchor_pos[0] << " "<< anchor_pos[1] << " "<< anchor_pos[2] << " " <<endl;KNOWN_ANCHOR = 1;Eigen::Vector3d eigen_anchor(anchor_pos[0],anchor_pos[1],anchor_pos[2]);ANCHOR_POS = eigen_anchor;}
}
小结
optimization函数是基于滑动窗口的优化方法最直接的体现,通过processImage函数在process线程中调用。要想理解optimization函数需要对于滑动窗口BA优化的原理搞清楚,对着公式原理,对着VINS的论文来看会好一些。VIR-SLAM是在VINS-mono的基础之上改来的,主要就是添加了uwb传感器进行优化限制vio的漂移,下一步希望根据这个代码进行一些论文的复现工作。
相关文章:

VIR-SLAM代码分析3——VIR_VINS详解之estimator.cpp/.h
前言 续接上一篇,本本篇接着介绍VIR-SLAM中estimator.cpp/.h文件的函数,尤其是和UWB相关的相比于VINS改动过的函数,仍然以具体功能情况代码注释的形式进行介绍。 重点函数介绍 优化函数,代码是先优化,后边缘化。 …...

大模型的RPA应用 | 代理流程自动化(APA),开启智能自动化新纪元
随着技术创新的持续推进,自动化技术已经变得至关重要,成为驱动企业和社会向前发展的核心动力。在自动化的里程碑中,机器人流程自动化(RPA)已经有效地将简单、重复且规则性的任务自动化。可是随着对处理更为复杂、多变且…...

爬虫学习 异步爬虫(五)
多线程 多进程 协程 进程 运行中的程序 线程 被CPU调度的执行过程,操作系统 运算调度的min单位 在进程之中,进程中实际运作单位 from threading import Thread#创建任务 def func(name):for i in range(100):print(name,i)if __name__ __main__:#创建线程t1 Thread(target …...

【Openstack Train安装】六、Keystone安装
OpenStack是一个云计算平台的项目,其中Keystone是一个身份认证服务组件,它提供了认证、授权和目录的服务。其他OpenStack服务组件都需要使用Keystone来验证用户的身份和权限,并且彼此之间需要相互协作。当一个OpenStack服务组件接收到用户的请…...

java学习part22包装类
119-面向对象(高级)-包装类的理解_基本数据类型与包装类间的转换_哔哩哔哩_bilibili 1.包装类 2.基本转包装方式 2.1new方式 源码 2.2valueof() 3.包装转基本 4.基本类型和包装类型的默认值不一样 比如boolean默认false Boolean默认null(对…...
【场景测试用例】二维码
测试思路: UI 不同设备,不同浏览器下的外观和布局一致用户友好性 二维码足够清晰且大小合适是否有错误提示是否有扫描成功/失败提示启动,扫描过程 功能 验证识别功能 二维码完整且有效二维码失效二维码不完整/过于模糊空白二维码测试不同大小…...

如何提高销售技巧,增加客户的成交率?
如何提高销售技巧,增加客户的成交率? 在如今的市场环境中,销售技巧的高低往往决定了你是否能够成功地打动客户的心。想要提高销售业绩,除了产品质量和服务的保障,更需要你精进销售技巧,从而让客户愿意为你…...

软件设计之生成器模式
理解生成器模式在于:一个对象若由多个部分组成,只要构建好这些部分然后拼接到一起就组成了一个完整的对象。比如一台电脑,它的类型可以不一样,可以是苹果的,可以是联想的,等等。同一款电脑它的组件也不一样…...

【Vulnhub 靶场】【CEREAL: 1】【困难】【20210529】
1、环境介绍 靶场介绍:https://www.vulnhub.com/entry/cereal-1,703/ 靶场下载:https://download.vulnhub.com/cereal/Cereal.ova 靶场难度:困难 发布日期:2021年5月29日 文件大小:1.1 GB 靶场作者:Thomas…...

【Vulnhub靶机】Jarbas--Jenkins
文章目录 信息收集主机发现端口扫描目录爆破 漏洞探测whatwebhash-identifierwhatweb 文档说明:https://www.vulnhub.com/entry/jarbas-1,232/ 靶机下载:Download (Mirror): 信息收集 主机发现 扫描C段 sudo nmap -sn 10.9.75.0/24端口扫描 sudo nma…...
Java面向对象第8天
精华笔记: 接口: 是一种引用数据类型 由interface定义 只能包含常量和抽象方法 不能被实例化 接口是需要被实现/继承的,实现类/派生类:必须重写接口中的所有抽象方法 一个类可以实现多个接口,用逗号分隔。若又继承…...

数据结构与算法复习笔记
1.数据结构基本概念 数据结构: 它是研究计算机数据间关系,包括数据的逻辑结构和存储结构及其操作。 数据(Data):数据即信息的载体,是能够输入到计算机中并且能被计算机识别、存储和处理的符号总称。 数据元素…...

关于微服务的思考
目录 什么是微服务 定义 特点 利弊 引入时机 需要哪些治理环节 从单体架构到微服务架构的演进 单体架构 集群和垂直化 SOA 微服务架构 如何实现微服务架构 服务拆分 主流微服务解决方案 基础设施 下一代微服务架构Service Mesh 什么是Service Mesh?…...

计算机毕业设计 基于Web的课程设计选题管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…...

群晖NAS:docker(Container Manager)、npm安装Verdaccio并常见命令集合
群晖NAS:docker(Container Manager)、npm安装Verdaccio并常见命令集合 自建 npm 资源库,使用Verdaccio。如果觉得麻烦,直接可以在外网注册 https://www.npmjs.com/ 网站。大同小异,自己搭建搭建方便局域网…...

老师旁听公开课到底听什么
经常参加公开课是老师提升自己教学水平的一种方式。那么,在旁听公开课时,老师应该听什么呢? 听课堂氛围 一堂好的公开课,应该能够让学生积极参与,课堂气氛活跃,而不是老师一个人唱独角戏。如果老师能够引导…...

一文让你深入了解JavaSE的知识点
꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …...

人体是否有清除hpv病毒能力?北京劲松HPV诊疗中心提出观点
HPV,全称人乳头瘤病毒,是一种常见的性传播疾病,其症状包括尖锐湿疣、皮肤疣等。那么,人体是否有清除HPV病毒的能力呢?答案是肯定的,人体确实具有清除HPV病毒的能力。 首先,我们要了解HPV病毒是如何感染…...
Linux下~目录和home目录的区别
在 Linux 中,~(波浪号)路径和 home 路径都与用户的主目录(home directory)相关。 ~(波浪号)路径:表示当前登录用户的主目录。例如,如果你当前是以用户user1的身份登陆&am…...

(二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
1 下载 Sublime Text 3 免安装版 Download - Sublime Text 2 下载 Package Control,放到 Sublime Text Build 3211\Data\Installed Packages 目录下。 Installation - Package Control 3 页面搜索 anaconda anaconda - Search - Package Control Anaconda - Pac…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...

HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...