2021SC@SDUSC
ImuTypes.ccCopyFrom函数;复制上一帧的预积分;pImuPre为上一帧的预积分
void Preintegrated::CopyFrom(Preintegrated* pImuPre)
{
std::cout << "Preintegrated: start clone" << std::endl;
dT = pImuPre->dT;
C = pImuPre->C.clone();
Info = pImuPre->Info.clone();
Nga = pImuPre->Nga.clone();
NgaWalk = pImuPre->NgaWalk.clone();
std::cout << "Preintegrated: first clone" << std::endl;
b.CopyFrom(pImuPre->b);
dR = pImuPre->dR.clone();
dV = pImuPre->dV.clone();
dP = pImuPre->dP.clone();
// 旋转关于陀螺仪偏置变化的Jacobian,以此类推
JRg = pImuPre->JRg.clone();
JVg = pImuPre->JVg.clone();
JVa = pImuPre->JVa.clone();
JPg = pImuPre->JPg.clone();
JPa = pImuPre->JPa.clone();
avgA = pImuPre->avgA.clone();
avgW = pImuPre->avgW.clone();
std::cout << "Preintegrated: second clone" << std::endl;
bu.CopyFrom(pImuPre->bu);
db = pImuPre->db.clone();
std::cout << "Preintegrated: third clone" << std::endl;
mvMeasurements = pImuPre->mvMeasurements;
std::cout << "Preintegrated: end clone" << std::endl;
}
Initialize函数,初始化预积分,
void Preintegrated::Initialize(const Bias &b_)
{
dR = cv::Mat::eye(3, 3, CV_32F);
dV = cv::Mat::zeros(3, 1, CV_32F);
dP = cv::Mat::zeros(3, 1, CV_32F);
JRg = cv::Mat::zeros(3, 3, CV_32F);
JVg = cv::Mat::zeros(3, 3, CV_32F);
JVa = cv::Mat::zeros(3, 3, CV_32F);
JPg = cv::Mat::zeros(3, 3, CV_32F);
JPa = cv::Mat::zeros(3, 3, CV_32F);
C = cv::Mat::zeros(15, 15, CV_32F);
Info = cv::Mat();
db = cv::Mat::zeros(6, 1, CV_32F);
b = b_;
bu = b_; // 更新后的偏置
avgA = cv::Mat::zeros(3, 1, CV_32F); // 平均加速度
avgW = cv::Mat::zeros(3, 1, CV_32F); // 平均角速度
dT = 0.0f;
mvMeasurements.clear(); // 存放imu数据及dt
}
Reintegrate函数根据新的偏置重新积分mvMeasurements里的数据 Optimizer::InertialOptimization调用。
void Preintegrated::Reintegrate()
{
std::unique_lock<std::mutex> lock(mMutex);
const std::vector<integrable> aux = mvMeasurements;
Initialize(bu);
for(size_t i=0;i<aux.size();i++)
IntegrateNewMeasurement(aux[i].a,aux[i].w,aux[i].t);
}
IntegrateNewMeasurement,预积分计算,更新noise
Step 1.构造协方差矩阵
Step 2. 构造函数,会根据更新后的bias进行角度积分
Step 3.更新协方差,frost经典预积分论文的第63个公式,推导了噪声(ηa, ηg)对dR dV dP 的影响
void Preintegrated::IntegrateNewMeasurement(const cv::Point3f &acceleration, const cv::Point3f &angVel, const float &dt)
{
// 保存imu数据,利用中值积分的结果构造一个预积分类保存在mvMeasurements中
mvMeasurements.push_back(integrable(acceleration,angVel,dt));
// ? 位姿第一个被更新,速度第二(因为这两个只依赖前一帧计算的旋转矩阵和速度),后面再更新旋转角度
// 噪声矩阵的传递矩阵,这部分用于计算i到j-1历史噪声或者协方差
cv::Mat A = cv::Mat::eye(9,9,CV_32F);
// 噪声矩阵的传递矩阵,这部分用于计算j-1新的噪声或协方差,这两个矩阵里面的数都是当前时刻的,计算主要是为了下一时刻使用
cv::Mat B = cv::Mat::zeros(9,6,CV_32F);
// 考虑偏置后的加速度、角速度
cv::Mat acc = (cv::Mat_<float>(3,1) << acceleration.x-b.bax,acceleration.y-b.bay, acceleration.z-b.baz);
cv::Mat accW = (cv::Mat_<float>(3,1) << angVel.x-b.bwx, angVel.y-b.bwy, angVel.z-b.bwz);
// 记录平均加速度和角速度
avgA = (dT*avgA + dR*acc*dt)/(dT+dt);
avgW = (dT*avgW + accW*dt)/(dT+dt);
// Update delta position dP and velocity dV (rely on no-updated delta rotation)
// 根据没有更新的dR来更新dP与dV eq.(38)
dP = dP + dV*dt + 0.5f*dR*acc*dt*dt; // 对应viorb论文的公式(2)的第三个,位移积分
dV = dV + dR*acc*dt; // 对应viorb论文的公式(2)的第二个,速度积分
// Compute velocity and position parts of matrices A and B (rely on non-updated delta rotation)
// 根据η_ij = A * η_i,j-1 + B_j-1 * η_j-1中的A矩阵和B矩阵对速度和位移进行更新
cv::Mat Wacc = (cv::Mat_<float>(3,3) << 0, -acc.at<float>(2), acc.at<float>(1),
acc.at<float>(2), 0, -acc.at<float>(0),
-acc.at<float>(1), acc.at<float>(0), 0);
A.rowRange(3,6).colRange(0,3) = -dR*dt*Wacc;
A.rowRange(6,9).colRange(0,3) = -0.5f*dR*dt*dt*Wacc;
A.rowRange(6,9).colRange(3,6) = cv::Mat::eye(3,3,CV_32F)*dt;
B.rowRange(3,6).colRange(3,6) = dR*dt;
B.rowRange(6,9).colRange(3,6) = 0.5f*dR*dt*dt;
// Update position and velocity jacobians wrt bias correction
// 更新bias雅克比,计算偏置的雅克比矩阵,pv 分别对ba与bg的偏导数
// 因为随着时间推移,不可能每次都重新计算雅克比矩阵,所以需要做J(k+1) = j(k) + (~)这类事,分解方式与AB矩阵相同
JPa = JPa + JVa*dt -0.5f*dR*dt*dt;
JPg = JPg + JVg*dt -0.5f*dR*dt*dt*Wacc*JRg
JVa = JVa - dR*dt;
JVg = JVg - dR*dt*Wacc*JRg;
// Update delta rotation
IntegratedRotation dRi(angVel,b,dt);
// 强行归一化使其符合旋转矩阵的格式
dR = NormalizeRotation(dR*dRi.deltaR);
// Compute rotation parts of matrices A and B
// 补充AB矩阵
A.rowRange(0,3).colRange(0,3) = dRi.deltaR.t();
B.rowRange(0,3).colRange(0,3) = dRi.rightJ*dt;
// 小量delta初始为0,更新后通常也为0,故省略了小量的更新
// Update covariance
C.rowRange(0,9).colRange(0,9) = A*C.rowRange(0,9).colRange(0,9)*A.t() + B*Nga*B.t(); // B矩阵为9*6矩阵 Nga 6*6对角矩阵,3个陀螺仪噪声的平方,3个加速度计噪声的平方
// 这一部分最开始是0矩阵,随着积分次数增加,每次都加上随机游走,偏置的信息矩阵
C.rowRange(9,15).colRange(9,15) = C.rowRange(9,15).colRange(9,15) + NgaWalk; // NgaWalk 6*6 随机游走对角矩阵
// Update rotation jacobian wrt bias correction
// 计算偏置的雅克比矩阵,r对bg的导数,∂ΔRij/∂bg = (ΔRjj-1) * ∂ΔRij-1/∂bg - Jr(j-1)*t
// 这里必须先更新dRi才能更新到这个值
JRg = dRi.deltaR.t()*JRg - dRi.rightJ*dt;
// Total integrated time
// 更新总时间
dT += dt;
}
MergePrevious函数中,融合两个预积分,发生在删除关键帧的时候,3帧变2帧,需要把两段预积分融合
void Preintegrated::MergePrevious(Preintegrated* pPrev)
{
if (pPrev==this)
return;
std::unique_lock<std::mutex> lock1(mMutex);
std::unique_lock<std::mutex> lock2(pPrev->mMutex);
Bias bav;
bav.bwx = bu.bwx;
bav.bwy = bu.bwy;
bav.bwz = bu.bwz;
bav.bax = bu.bax;
bav.bay = bu.bay;
bav.baz = bu.baz;
const std::vector<integrable > aux1 = pPrev->mvMeasurements;
const std::vector<integrable> aux2 = mvMeasurements;
Initialize(bav);
for(size_t i=0;i<aux1.size();i++)
IntegrateNewMeasurement(aux1[i].a,aux1[i].w,aux1[i].t);
for(size_t i=0;i<aux2.size();i++)
IntegrateNewMeasurement(aux2[i].a,aux2[i].w,aux2[i].t);
}
GetDeltaBias获得当前偏置与输入偏置的改变量
IMU::Bias Preintegrated::GetDeltaBias(const Bias &b_)
{
std::unique_lock<std::mutex> lock(mMutex);
return IMU::Bias(b_.bax-b.bax,b_.bay-b.bay,b_.baz-b.baz,b_.bwx-b.bwx,b_.bwy-b.bwy,b_.bwz-b.bwz);
}
GetDeltaRotation根据新的偏置计算新的dR
cv::Mat Preintegrated::GetDeltaRotation(const Bias &b_)
{
std::unique_lock<std::mutex> lock(mMutex);
// 计算偏置的变化量
cv::Mat dbg = (cv::Mat_<float>(3,1) << b_.bwx-b.bwx,b_.bwy-b.bwy,b_.bwz-b.bwz);
// 考虑偏置后,dR对偏置线性化的近似求解
return NormalizeRotation(dR*ExpSO3(JRg*dbg));
}
GetDeltaVelocity根据新的偏置计算新的dV
cv::Mat Preintegrated::GetDeltaVelocity(const Bias &b_)
{
std::unique_lock<std::mutex> lock(mMutex);
cv::Mat dbg = (cv::Mat_<float>(3,1) << b_.bwx-b.bwx,b_.bwy-b.bwy,b_.bwz-b.bwz);
cv::Mat dba = (cv::Mat_<float>(3,1) << b_.bax-b.bax,b_.bay-b.bay,b_.baz-b.baz);
return dV + JVg*dbg + JVa*dba;
}
GetDeltaPosition根据新的偏置计算新的dP
cv::Mat Preintegrated::GetDeltaPosition(const Bias &b_)
{
std::unique_lock<std::mutex> lock(mMutex);
cv::Mat dbg = (cv::Mat_<float>(3,1) << b_.bwx-b.bwx,b_.bwy-b.bwy,b_.bwz-b.bwz);
cv::Mat dba = (cv::Mat_<float>(3,1) << b_.bax-b.bax,b_.bay-b.bay,b_.baz-b.baz);
// 考虑偏置后,dP对偏置线性化的近似求解
return dP + JPg*dbg + JPa*dba;
}
GetUpdatedDeltaRotation返回经过db(δba, δbg)更新后的dR(return dR)
cv::Mat Preintegrated::GetUpdatedDeltaRotation()
{
std::unique_lock<std::mutex> lock(mMutex);
return NormalizeRotation(dR*ExpSO3(JRg*db.rowRange(0,3)));
}
GetUpdatedDeltaVelocity返回经过db(δba, δbg)更新后的dV(return dV)
cv::Mat Preintegrated::GetUpdatedDeltaVelocity()
{
std::unique_lock<std::mutex> lock(mMutex);
return dV + JVg*db.rowRange(0,3) + JVa*db.rowRange(3,6);
}
GetUpdatedDeltaPosition返回经过db(δba, δbg)更新后的dP(return dP)
cv::Mat Preintegrated::GetUpdatedDeltaPosition()
{
std::unique_lock<std::mutex> lock(mMutex);
return dP + JPg*db.rowRange(0,3) + JPa*db.rowRange(3,6);
}
Set设置参数,其中Tbc_ 为位姿变换,ng、na为噪声,ngw、naw为随机游走
void Calib::Set(const cv::Mat &Tbc_, const float &ng, const float &na, const float &ngw, const float &naw)
{
Tbc = Tbc_.clone();
Tcb = cv::Mat::eye(4,4,CV_32F);
Tcb.rowRange(0,3).colRange(0,3) = Tbc.rowRange(0,3).colRange(0,3).t();
Tcb.rowRange(0,3).col(3) = -Tbc.rowRange(0,3).colRange(0,3).t()*Tbc.rowRange(0,3).col(3);
// 噪声协方差
Cov = cv::Mat::eye(6,6,CV_32F);
const float ng2 = ng*ng;
const float na2 = na*na;
Cov.at<float>(0,0) = ng2;
Cov.at<float>(1,1) = ng2;
Cov.at<float>(2,2) = ng2;
Cov.at<float>(3,3) = na2;
Cov.at<float>(4,4) = na2;
Cov.at<float>(5,5) = na2;
// 随机游走协方差
CovWalk = cv::Mat::eye(6,6,CV_32F);
const float ngw2 = ngw*ngw;
const float naw2 = naw*naw;
CovWalk.at<float>(0,0) = ngw2;
CovWalk.at<float>(1,1) = ngw2;
CovWalk.at<float>(2,2) = ngw2;
CovWalk.at<float>(3,3) = naw2;
CovWalk.at<float>(4,4) = naw2;
CovWalk.at<float>(5,5) = naw2;
}
Calib函数,imu标定参数的构造函数;calib为imu标定参数
Calib::Calib(const Calib &calib)
{
Tbc = calib.Tbc.clone();
Tcb = calib.Tcb.clone();
Cov = calib.Cov.clone();
CovWalk = calib.CovWalk.clone();
}