当前位置: 首页 > news >正文

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

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

大模型的RPA应用 | 代理流程自动化(APA),开启智能自动化新纪元

随着技术创新的持续推进&#xff0c;自动化技术已经变得至关重要&#xff0c;成为驱动企业和社会向前发展的核心动力。在自动化的里程碑中&#xff0c;机器人流程自动化&#xff08;RPA&#xff09;已经有效地将简单、重复且规则性的任务自动化。可是随着对处理更为复杂、多变且…...

爬虫学习 异步爬虫(五)

多线程 多进程 协程 进程 运行中的程序 线程 被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是一个云计算平台的项目&#xff0c;其中Keystone是一个身份认证服务组件&#xff0c;它提供了认证、授权和目录的服务。其他OpenStack服务组件都需要使用Keystone来验证用户的身份和权限&#xff0c;并且彼此之间需要相互协作。当一个OpenStack服务组件接收到用户的请…...

java学习part22包装类

119-面向对象(高级)-包装类的理解_基本数据类型与包装类间的转换_哔哩哔哩_bilibili 1.包装类 2.基本转包装方式 2.1new方式 源码 2.2valueof&#xff08;&#xff09; 3.包装转基本 4.基本类型和包装类型的默认值不一样 比如boolean默认false Boolean默认null&#xff08;对…...

【场景测试用例】二维码

测试思路&#xff1a; UI 不同设备&#xff0c;不同浏览器下的外观和布局一致用户友好性 二维码足够清晰且大小合适是否有错误提示是否有扫描成功/失败提示启动&#xff0c;扫描过程 功能 验证识别功能 二维码完整且有效二维码失效二维码不完整/过于模糊空白二维码测试不同大小…...

如何提高销售技巧,增加客户的成交率?

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

软件设计之生成器模式

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

【Vulnhub 靶场】【CEREAL: 1】【困难】【20210529】

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

【Vulnhub靶机】Jarbas--Jenkins

文章目录 信息收集主机发现端口扫描目录爆破 漏洞探测whatwebhash-identifierwhatweb 文档说明&#xff1a;https://www.vulnhub.com/entry/jarbas-1,232/ 靶机下载&#xff1a;Download (Mirror): 信息收集 主机发现 扫描C段 sudo nmap -sn 10.9.75.0/24端口扫描 sudo nma…...

Java面向对象第8天

精华笔记&#xff1a; 接口&#xff1a; 是一种引用数据类型 由interface定义 只能包含常量和抽象方法 不能被实例化 接口是需要被实现/继承的&#xff0c;实现类/派生类&#xff1a;必须重写接口中的所有抽象方法 一个类可以实现多个接口&#xff0c;用逗号分隔。若又继承…...

数据结构与算法复习笔记

1.数据结构基本概念 数据结构: 它是研究计算机数据间关系&#xff0c;包括数据的逻辑结构和存储结构及其操作。 数据&#xff08;Data&#xff09;&#xff1a;数据即信息的载体&#xff0c;是能够输入到计算机中并且能被计算机识别、存储和处理的符号总称。 数据元素&#xf…...

关于微服务的思考

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

计算机毕业设计 基于Web的课程设计选题管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

群晖NAS:docker(Container Manager)、npm安装Verdaccio并常见命令集合

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

老师旁听公开课到底听什么

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

一文让你深入了解JavaSE的知识点

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

人体是否有清除hpv病毒能力?北京劲松HPV诊疗中心提出观点

​HPV&#xff0c;全称人乳头瘤病毒&#xff0c;是一种常见的性传播疾病&#xff0c;其症状包括尖锐湿疣、皮肤疣等。那么&#xff0c;人体是否有清除HPV病毒的能力呢?答案是肯定的&#xff0c;人体确实具有清除HPV病毒的能力。 首先&#xff0c;我们要了解HPV病毒是如何感染…...

Linux下~目录和home目录的区别

在 Linux 中&#xff0c;~&#xff08;波浪号&#xff09;路径和 home 路径都与用户的主目录&#xff08;home directory&#xff09;相关。 ~&#xff08;波浪号&#xff09;路径&#xff1a;表示当前登录用户的主目录。例如&#xff0c;如果你当前是以用户user1的身份登陆&am…...

(二) Windows 下 Sublime Text 3 安装离线插件 Anaconda

1 下载 Sublime Text 3 免安装版 Download - Sublime Text 2 下载 Package Control&#xff0c;放到 Sublime Text Build 3211\Data\Installed Packages 目录下。 Installation - Package Control 3 页面搜索 anaconda anaconda - Search - Package Control Anaconda - Pac…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

Python爬虫(四):PyQuery 框架

PyQuery 框架详解与对比 BeautifulSoup 第一部分&#xff1a;PyQuery 框架介绍 1. PyQuery 是什么&#xff1f; PyQuery 是一个 Python 的 HTML/XML 解析库&#xff0c;它采用了 jQuery 的语法风格&#xff0c;让开发者能够用类似前端 jQuery 的方式处理文档解析。它的核心特…...