更新标注

master
小白逆袭 2021-10-26 23:30:10 +08:00
parent 965140d945
commit 8dcefb5567
6 changed files with 163 additions and 35 deletions

View File

@ -67,7 +67,7 @@ Eigen::Matrix3d InverseRightJacobianSO3(const double x, const double y, const do
Eigen::Matrix3d NormalizeRotation(const Eigen::Matrix3d &R);
// 相关节点中使用存放的是imu与cam的内外参
class ImuCamPose
{
public:
@ -103,9 +103,10 @@ public:
Eigen::Matrix3d Rwb0;
Eigen::Matrix3d DR;
int its;
int its; // 记录更新次数
};
// 逆深度点,后面节点虽然有用到,但是声明的节点并没有使用到,暂时不看
class InvDepthPoint
{
public:
@ -124,6 +125,7 @@ public:
};
// Optimizable parameters are IMU pose
// 优化中关于位姿的节点6自由度
class VertexPose : public g2o::BaseVertex<6,ImuCamPose>
{
public:
@ -140,15 +142,21 @@ public:
virtual bool read(std::istream& is);
virtual bool write(std::ostream& os) const;
// 重置函数,设定被优化变量的原始值
virtual void setToOriginImpl() {
}
// 更新
virtual void oplusImpl(const double* update_){
_estimate.Update(update_);
// https://github.com/RainerKuemmerle/g2o/blob/master/doc/README_IF_IT_WAS_WORKING_AND_IT_DOES_NOT.txt
// 官方讲解cache
// 需要在oplusImpl与setEstimate函数中添加
updateCache();
}
};
// 优化中关于位姿的节点4自由度 3个平移加一个航偏
class VertexPose4DoF : public g2o::BaseVertex<4,ImuCamPose>
{
// Translation and yaw are the only optimizable variables
@ -172,6 +180,7 @@ public:
virtual void setToOriginImpl() {
}
// 强制让旋转的前两维的更新量为0
virtual void oplusImpl(const double* update_){
double update6DoF[6];
update6DoF[0] = 0;
@ -185,6 +194,9 @@ public:
}
};
/**
* @brief
*/
class VertexVelocity : public g2o::BaseVertex<3,Eigen::Vector3d>
{
public:
@ -206,6 +218,9 @@ public:
}
};
/**
* @brief
*/
class VertexGyroBias : public g2o::BaseVertex<3,Eigen::Vector3d>
{
public:
@ -227,7 +242,9 @@ public:
}
};
/**
* @brief
*/
class VertexAccBias : public g2o::BaseVertex<3,Eigen::Vector3d>
{
public:
@ -251,6 +268,7 @@ public:
// Gravity direction vertex
// 重力方向
class GDirection
{
public:
@ -268,6 +286,9 @@ public:
int its;
};
/**
* @brief
*/
class VertexGDir : public g2o::BaseVertex<2,GDirection>
{
public:
@ -290,6 +311,9 @@ public:
};
// scale vertex
/**
* @brief
*/
class VertexScale : public g2o::BaseVertex<1,double>
{
public:
@ -315,6 +339,9 @@ public:
// Inverse depth point (just one parameter, inverse depth at the host frame)
/**
* @brief
*/
class VertexInvDepth : public g2o::BaseVertex<1,InvDepthPoint>
{
public:
@ -337,12 +364,13 @@ public:
};
/**
* @brief
* @brief
* OptimizableTypes.h
* imu
* imu姿imu姿
* imu使
*/
// 误差为2维 类型为Eigen::Vector2d 节点1类型为g2o::VertexSBAPointXYZ节点二类型为VertexPose
class EdgeMono : public g2o::BaseBinaryEdge<2,Eigen::Vector2d,g2o::VertexSBAPointXYZ,VertexPose>
{
public:
@ -354,11 +382,12 @@ public:
virtual bool read(std::istream& is){return false;}
virtual bool write(std::ostream& os) const{return false;}
// 计算重投影误差
void computeError(){
const g2o::VertexSBAPointXYZ* VPoint = static_cast<const g2o::VertexSBAPointXYZ*>(_vertices[0]);
const VertexPose* VPose = static_cast<const VertexPose*>(_vertices[1]);
const Eigen::Vector2d obs(_measurement);
_error = obs - VPose->estimate().Project(VPoint->estimate(),cam_idx);
_error = obs - VPose->estimate().Project(VPoint->estimate(),cam_idx); // 投影
}
@ -379,6 +408,7 @@ public:
return J;
}
// 由2*2的像素点信息矩阵变成了9*9的关于旋转平移与三维点坐标的信息矩阵
Eigen::Matrix<double,9,9> GetHessian(){
linearizeOplus();
Eigen::Matrix<double,2,9> J;
@ -391,6 +421,9 @@ public:
const int cam_idx;
};
/**
* @brief 姿
*/
class EdgeMonoOnlyPose : public g2o::BaseUnaryEdge<2,Eigen::Vector2d,VertexPose>
{
public:
@ -426,11 +459,15 @@ public:
const int cam_idx;
};
/**
* @brief 姿
*/
class EdgeStereo : public g2o::BaseBinaryEdge<3,Eigen::Vector3d,g2o::VertexSBAPointXYZ,VertexPose>
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
// 代码中都是0
EdgeStereo(int cam_idx_=0): cam_idx(cam_idx_){}
virtual bool read(std::istream& is){return false;}
@ -466,7 +503,9 @@ public:
const int cam_idx;
};
/**
* @brief 姿
*/
class EdgeStereoOnlyPose : public g2o::BaseUnaryEdge<3,Eigen::Vector3d,VertexPose>
{
public:
@ -497,6 +536,9 @@ public:
};
// TO COMMENT
/**
* @brief
*/
class EdgeInertial : public g2o::BaseMultiEdge<9,Vector9d>
{
public:
@ -510,6 +552,7 @@ public:
void computeError();
virtual void linearizeOplus();
// 关于pose1与2 的旋转平移速度,以及之间的偏置的信息矩阵
Eigen::Matrix<double,24,24> GetHessian(){
linearizeOplus();
Eigen::Matrix<double,9,24> J;
@ -522,6 +565,7 @@ public:
return J.transpose()*information()*J;
}
// 没用
Eigen::Matrix<double,18,18> GetHessianNoPose1(){
linearizeOplus();
Eigen::Matrix<double,9,18> J;
@ -533,6 +577,7 @@ public:
return J.transpose()*information()*J;
}
// 关于pose2 的旋转平移信息矩阵
Eigen::Matrix<double,9,9> GetHessian2(){
linearizeOplus();
Eigen::Matrix<double,9,9> J;
@ -541,14 +586,18 @@ public:
return J.transpose()*information()*J;
}
// 预积分中对应的状态对偏置的雅可比
const Eigen::Matrix3d JRg, JVg, JPg;
const Eigen::Matrix3d JVa, JPa;
IMU::Preintegrated* mpInt;
const double dt;
Eigen::Vector3d g;
IMU::Preintegrated* mpInt; // 预积分
const double dt; // 预积分时间
Eigen::Vector3d g; // 0, 0, -IMU::GRAVITY_VALUE
};
/**
* @brief
*/
// Edge inertial whre gravity is included as optimizable variable and it is not supposed to be pointing in -z axis, as well as scale
class EdgeInertialGS : public g2o::BaseMultiEdge<9,Vector9d>
{
@ -570,6 +619,7 @@ public:
const double dt;
Eigen::Vector3d g, gI;
// 关于pose1与2 的旋转平移速度,以及之间的偏置,还有重力方向与尺度的信息矩阵
Eigen::Matrix<double,27,27> GetHessian(){
linearizeOplus();
Eigen::Matrix<double,9,27> J;
@ -584,6 +634,7 @@ public:
return J.transpose()*information()*J;
}
// 与上面摆放不同
Eigen::Matrix<double,27,27> GetHessian2(){
linearizeOplus();
Eigen::Matrix<double,9,27> J;
@ -598,6 +649,7 @@ public:
return J.transpose()*information()*J;
}
// 关于偏置,重力方向与尺度的信息矩阵
Eigen::Matrix<double,9,9> GetHessian3(){
linearizeOplus();
Eigen::Matrix<double,9,9> J;
@ -609,7 +661,7 @@ public:
}
// 下面的没有用到,其实也是获取状态的信息矩阵
Eigen::Matrix<double,1,1> GetHessianScale(){
linearizeOplus();
Eigen::Matrix<double,9,1> J = _jacobianOplus[7];
@ -636,7 +688,9 @@ public:
};
/**
* @brief
*/
class EdgeGyroRW : public g2o::BaseBinaryEdge<3,Eigen::Vector3d,VertexGyroBias,VertexGyroBias>
{
public:
@ -672,7 +726,9 @@ public:
}
};
/**
* @brief
*/
class EdgeAccRW : public g2o::BaseBinaryEdge<3,Eigen::Vector3d,VertexAccBias,VertexAccBias>
{
public:
@ -708,6 +764,9 @@ public:
}
};
/**
* @brief
*/
class ConstraintPoseImu
{
public:
@ -717,7 +776,8 @@ public:
const Eigen::Vector3d &bg_, const Eigen::Vector3d &ba_, const Matrix15d &H_):
Rwb(Rwb_), twb(twb_), vwb(vwb_), bg(bg_), ba(ba_), H(H_)
{
H = (H+H)/2;
H = (H+H)/2; // 对称化
// 令特征值小的位置变为0
Eigen::SelfAdjointEigenSolver<Eigen::Matrix<double,15,15> > es(H);
Eigen::Matrix<double,15,1> eigs = es.eigenvalues();
for(int i=0;i<15;i++)
@ -725,6 +785,8 @@ public:
eigs[i]=0;
H = es.eigenvectors()*eigs.asDiagonal()*es.eigenvectors().transpose();
}
// 形式不同
ConstraintPoseImu(const cv::Mat &Rwb_, const cv::Mat &twb_, const cv::Mat &vwb_,
const IMU::Bias &b, const cv::Mat &H_)
{
@ -753,6 +815,9 @@ public:
Matrix15d H;
};
/**
* @brief
*/
class EdgePriorPoseImu : public g2o::BaseMultiEdge<15,Vector15d>
{
public:
@ -775,6 +840,7 @@ public:
return J.transpose()*information()*J;
}
// 没用到,除了旋转平移外的信息矩阵
Eigen::Matrix<double,9,9> GetHessianNoPose(){
linearizeOplus();
Eigen::Matrix<double,15,9> J;
@ -789,6 +855,9 @@ public:
};
// Priors for biases
/**
* @brief
*/
class EdgePriorAcc : public g2o::BaseUnaryEdge<3,Eigen::Vector3d,VertexAccBias>
{
public:
@ -813,6 +882,9 @@ public:
const Eigen::Vector3d bprior;
};
/**
* @brief
*/
class EdgePriorGyro : public g2o::BaseUnaryEdge<3,Eigen::Vector3d,VertexGyroBias>
{
public:
@ -837,7 +909,9 @@ public:
const Eigen::Vector3d bprior;
};
/**
* @brief 4DOF
*/
class Edge4DoF : public g2o::BaseBinaryEdge<6,Vector6d,VertexPose4DoF,VertexPose4DoF>
{
public:

View File

@ -167,6 +167,9 @@ void ImuCamPose::SetParam(const std::vector<Eigen::Matrix3d> &_Rcw, const std::v
bf = _bf;
}
/**
* @brief
*/
Eigen::Vector2d ImuCamPose::Project(const Eigen::Vector3d &Xw, int cam_idx) const
{
Eigen::Vector3d Xc = Rcw[cam_idx]*Xw+tcw[cam_idx];
@ -174,6 +177,10 @@ Eigen::Vector2d ImuCamPose::Project(const Eigen::Vector3d &Xw, int cam_idx) cons
return pCamera[cam_idx]->project(Xc);
}
/**
* @brief 0
* @return u v u`
*/
Eigen::Vector3d ImuCamPose::ProjectStereo(const Eigen::Vector3d &Xw, int cam_idx) const
{
Eigen::Vector3d Pc = Rcw[cam_idx]*Xw+tcw[cam_idx];
@ -219,6 +226,7 @@ void ImuCamPose::Update(const double *pu)
}
// 更新世界坐标系
void ImuCamPose::UpdateW(const double *pu)
{
Eigen::Vector3d ur, ut;
@ -606,7 +614,7 @@ void EdgeInertial::linearizeOplus()
_jacobianOplus[3].block<3,3>(6,0) = -JPa; // OK
// Jacobians wrt Pose 2
// _jacobianOplus[3] 9*6矩阵 总体来说就是三个残差分别对pose2的旋转与平移p求导
// _jacobianOplus[4] 9*6矩阵 总体来说就是三个残差分别对pose2的旋转与平移p求导
_jacobianOplus[4].setZero();
// rotation
_jacobianOplus[4].block<3,3>(0,0) = invJr; // OK
@ -614,7 +622,7 @@ void EdgeInertial::linearizeOplus()
_jacobianOplus[4].block<3,3>(6,3) = Rbw1*Rwb2; // OK
// Jacobians wrt Velocity 2
// _jacobianOplus[3] 9*3矩阵 总体来说就是三个残差分别对pose2的速度求导
// _jacobianOplus[5] 9*3矩阵 总体来说就是三个残差分别对pose2的速度求导
_jacobianOplus[5].setZero();
_jacobianOplus[5].block<3,3>(3,0) = Rbw1; // OK
}
@ -930,6 +938,6 @@ Eigen::Matrix3d NormalizeRotation(const Eigen::Matrix3d &R)
// 2. 对于行列数不同的矩阵例如3*4 或者 4*3 矩阵只有3个奇异向量计算的时候如果是Thin 那么得出的UV矩阵列数只能是3如果是full那么就是4
// 3. thin会损失一部分数据但是会加快计算对于大型矩阵解算方程时可以用thin加速得到结果
Eigen::JacobiSVD<Eigen::Matrix3d> svd(R,Eigen::ComputeFullU | Eigen::ComputeFullV);
return svd.matrixU()*svd.matrixV();
return svd.matrixU()*svd.matrixV().transpose();
}
}

View File

@ -1601,6 +1601,7 @@ void LocalMapping::InitializeIMU(float priorG, float priorA, bool bFIBA)
if(mpCurrentKeyFrame->mTimeStamp-mFirstTs<minTime)
return;
// 正在做IMU的初始化在tracking里面使用如果为true暂不添加关键帧
bInitializing = true;
// 先处理新关键帧,防止堆积且保证数据量充足
@ -1626,20 +1627,21 @@ void LocalMapping::InitializeIMU(float priorG, float priorA, bool bFIBA)
continue;
if (!(*itKF)->mPrevKF)
continue;
// Rwbimu坐标转到初始化前世界坐标系下的坐标*更新偏置后的速度,可以理解为在世界坐标系下的速度矢量
// 初始化时关于速度的预积分定义Ri.t()*(s*Vj - s*Vi - Rwg*g*tij)
dirG -= (*itKF)->mPrevKF->GetImuRotation()*(*itKF)->mpImuPreintegrated->GetUpdatedDeltaVelocity();
// 求取实际的速度,位移/时间
cv::Mat _vel = ((*itKF)->GetImuPosition() - (*itKF)->mPrevKF->GetImuPosition())/(*itKF)->mpImuPreintegrated->dT;
(*itKF)->SetVelocity(_vel);
(*itKF)->mPrevKF->SetVelocity(_vel);
}
// dirG = sV1 - sVn + n*Rwg*g*t
// 归一化
dirG = dirG/cv::norm(dirG);
// 原本的重力方向
cv::Mat gI = (cv::Mat_<float>(3,1) << 0.0f, 0.0f, -1.0f);
// 求速度方向与重力方向的角轴
cv::Mat v = gI.cross(dirG);
// 求角轴
// 求角轴
const float nv = cv::norm(v);
// 求转角大小
const float cosg = gI.dot(dirG);
@ -1664,7 +1666,7 @@ void LocalMapping::InitializeIMU(float priorG, float priorA, bool bFIBA)
mInitTime = mpTracker->mLastFrame.mTimeStamp-vpKF.front()->mTimeStamp;
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
// 计算残差及偏置差,优化尺度重力方向及Ri Rj Vi Vj Pi Pj
// 计算残差及偏置差,优化尺度重力方向及速度偏置偏置先验为0双目时不优化尺度
Optimizer::InertialOptimization(mpAtlas->GetCurrentMap(), mRwg, mScale, mbg, mba, mbMonocular, infoInertial, false, false, priorG, priorA);
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
@ -1736,10 +1738,11 @@ void LocalMapping::InitializeIMU(float priorG, float priorA, bool bFIBA)
}
mbNewInit=true;
mnKFs=vpKF.size();
mIdxInit++;
mbNewInit=true; // 没用到
mnKFs=vpKF.size(); // 没用到
mIdxInit++; // 没用到
// 里面存放的是来到Local线程但还未处理的关键帧
for(list<KeyFrame*>::iterator lit = mlNewKeyFrames.begin(), lend=mlNewKeyFrames.end(); lit!=lend; lit++)
{
(*lit)->SetBadFlag();

View File

@ -298,6 +298,14 @@ void Map::RotateMap(const cv::Mat &R)
}
}
// 恢复尺度及重力方向
/** imu在localmapping中初始化LocalMapping::InitializeIMU中使用误差包含三个残差与两个偏置
* 使
* @param R Rgw
* @param s
* @param bScaledVel
* @param t cv::Mat::zeros(cv::Size(1,3),CV_32F)
*/
void Map::ApplyScaledRotation(const cv::Mat &R, const float s, const bool bScaledVel, const cv::Mat t)
{
unique_lock<mutex> lock(mMutexMap);
@ -310,19 +318,36 @@ void Map::ApplyScaledRotation(const cv::Mat &R, const float s, const bool bScale
cv::Mat Tyw = Tyx*Txw;
Tyw.rowRange(0,3).col(3) = Tyw.rowRange(0,3).col(3)+t;
cv::Mat Ryw = Tyw.rowRange(0,3).colRange(0,3);
cv::Mat tyw = Tyw.rowRange(0,3).col(3);
// Tyw 中旋转部分等于R平移部分等于t
// 做了很多操作到最后还是得出了一个R跟t感觉上面的操作像是预留了一些东西比如在世界坐标系与第一帧有一定Rt时只不过暂时没有用到
cv::Mat Ryw = Tyw.rowRange(0,3).colRange(0,3); // R
cv::Mat tyw = Tyw.rowRange(0,3).col(3); // t
for(set<KeyFrame*>::iterator sit=mspKeyFrames.begin(); sit!=mspKeyFrames.end(); sit++)
{
// 更新关键帧位姿
/**
* | Rw2w1 tw2w1 | * | Rw1c s*tw1c | = | Rw2c s*Rw2w1*tw1c + tw2w1 |
* | 0 1 | | 0 1 | | 0 1 |
* ssmpw2
*
* | s*Rw2w1 tw2w1 | * | Rw1c tw1c | = | s*Rw2c s*Rw2w1*tw1c + tw2w1 |
* | 0 1 | | 0 1 | | 0 1 |
*/
KeyFrame* pKF = *sit;
cv::Mat Twc = pKF->GetPoseInverse();
Twc.rowRange(0,3).col(3)*=s;
// | Ryc s*Ryw*twc + tyw |
// | 0 1 |
cv::Mat Tyc = Tyw*Twc;
cv::Mat Tcy = cv::Mat::eye(4,4,CV_32F);
Tcy.rowRange(0,3).colRange(0,3) = Tyc.rowRange(0,3).colRange(0,3).t();
Tcy.rowRange(0,3).col(3) = -Tcy.rowRange(0,3).colRange(0,3)*Tyc.rowRange(0,3).col(3);
pKF->SetPose(Tcy);
// 更新关键帧速度
cv::Mat Vw = pKF->GetVelocity();
if(!bScaledVel)
pKF->SetVelocity(Ryw*Vw);
@ -332,6 +357,7 @@ void Map::ApplyScaledRotation(const cv::Mat &R, const float s, const bool bScale
}
for(set<MapPoint*>::iterator sit=mspMapPoints.begin(); sit!=mspMapPoints.end(); sit++)
{
// 更新每一个mp在世界坐标系下的坐标
MapPoint* pMP = *sit;
pMP->SetWorldPos(s*Ryw*pMP->GetWorldPos()+tyw);
pMP->UpdateNormalAndDepth();

View File

@ -5069,7 +5069,8 @@ Eigen::MatrixXd Optimizer::Sparsify(const Eigen::MatrixXd &H, const int &start1,
}
void Optimizer::InertialOptimization(Map *pMap, Eigen::Matrix3d &Rwg, double &scale, Eigen::Vector3d &bg, Eigen::Vector3d &ba, bool bMono, Eigen::MatrixXd &covInertial, bool bFixedVel, bool bGauss, float priorG, float priorA)
void Optimizer::InertialOptimization(Map *pMap, Eigen::Matrix3d &Rwg, double &scale, Eigen::Vector3d &bg, Eigen::Vector3d &ba,
bool bMono, Eigen::MatrixXd &covInertial, bool bFixedVel, bool bGauss, float priorG, float priorA)
{
Verbose::PrintMess("inertial optimization", Verbose::VERBOSITY_NORMAL);
int its = 200; // Check number of iterations

View File

@ -4582,12 +4582,25 @@ void Tracking::InformOnlyTracking(const bool &flag)
mbOnlyTracking = flag;
}
/**
* @brief 姿姿
* localmappingimu使imu使imu线KF.
* 使frame使imu
*
* @param s
* @param b
* @param pCurrentKeyFrame
*/
void Tracking::UpdateFrameIMU(const float s, const IMU::Bias &b, KeyFrame* pCurrentKeyFrame)
{
Map * pMap = pCurrentKeyFrame->GetMap();
unsigned int index = mnFirstFrameId;
unsigned int index = mnFirstFrameId; // unused
// 每一帧的参考关键帧
list<ORB_SLAM3::KeyFrame*>::iterator lRit = mlpReferences.begin();
list<bool>::iterator lbL = mlbLost.begin();
list<bool>::iterator lbL = mlbLost.begin(); // 对应帧是否跟踪丢失
// mlRelativeFramePoses 存放的是Tcr
// 三个变量一一对应
for(list<cv::Mat>::iterator lit=mlRelativeFramePoses.begin(),lend=mlRelativeFramePoses.end();lit!=lend;lit++, lRit++, lbL++)
{
if(*lbL)
@ -4605,11 +4618,11 @@ void Tracking::UpdateFrameIMU(const float s, const IMU::Bias &b, KeyFrame* pCurr
(*lit).rowRange(0,3).col(3)=(*lit).rowRange(0,3).col(3)*s;
}
}
// 设置偏置
mLastBias = b;
// 设置上一关键帧如果说mpLastKeyFrame已经是经过添加的新的kf而pCurrentKeyFrame还是上一个kfmpLastKeyFrame直接指向之前的kf
mpLastKeyFrame = pCurrentKeyFrame;
// 更新偏置
mLastFrame.SetNewBias(mLastBias);
mCurrentFrame.SetNewBias(mLastBias);
@ -4622,10 +4635,12 @@ void Tracking::UpdateFrameIMU(const float s, const IMU::Bias &b, KeyFrame* pCurr
while(!mCurrentFrame.imuIsPreintegrated())
{
// 当前帧需要预积分完毕这段函数实在localmapping里调用的
usleep(500);
}
// frame的mpLastKeyFrame只是用于预积分imu模式
// TODO 如果上一帧正好是上一帧的上一关键帧mLastFrame.mpLastKeyFrame与mLastFrame不可能是一个可以验证一下
if(mLastFrame.mnId == mLastFrame.mpLastKeyFrame->mnFrameId)
{
mLastFrame.SetImuPoseVelocity(mLastFrame.mpLastKeyFrame->GetImuRotation(),
@ -4638,12 +4653,13 @@ void Tracking::UpdateFrameIMU(const float s, const IMU::Bias &b, KeyFrame* pCurr
Rwb1 = mLastFrame.mpLastKeyFrame->GetImuRotation();
Vwb1 = mLastFrame.mpLastKeyFrame->GetVelocity();
t12 = mLastFrame.mpImuPreintegrated->dT;
// 根据mLastFrame的上一个关键帧的信息此时已经经过imu初始化了所以关键帧的信息都是校正后的以及imu的预积分重新计算上一帧的位姿
mLastFrame.SetImuPoseVelocity(Rwb1*mLastFrame.mpImuPreintegrated->GetUpdatedDeltaRotation(),
twb1 + Vwb1*t12 + 0.5f*t12*t12*Gz+ Rwb1*mLastFrame.mpImuPreintegrated->GetUpdatedDeltaPosition(),
Vwb1 + Gz*t12 + Rwb1*mLastFrame.mpImuPreintegrated->GetUpdatedDeltaVelocity());
}
// 当前帧是否做了预积分
if (mCurrentFrame.mpImuPreintegrated)
{
twb1 = mCurrentFrame.mpLastKeyFrame->GetImuPosition();