LOAM学习-代码解析(一)点云数据配准 scanRegistration

9 篇文章 2 订阅

前言

在看完Zhang Ji写的LOAM论文,对LOAM的基本原理有了大概的了解,但对具体实现有点疑问,所以就想一步一步完整解析LOAM的代码。

LOAM代码(带中文注释)的地址:https://github.com/cuitaixiang/LOAM_NOTED

LOAM代码(带中文注释)的百度网盘链接: https://pan.baidu.com/s/1tVSNBxNQrxKJyd5c9mWFWw 提取码: wwxr

LOAM论文的百度网盘链接: https://pan.baidu.com/s/10ahqg8O3G2-xOt9QZ1GuEQ 提取码: hnri

LOAM流程如下图所示
在这里插入图片描述

点云数据配准-scanRegistration

点云数据配准的函数为scanRegistration,首先看到的是对于坐标系的解释说明,如下

  1. imu为x轴向前,y轴向左,z轴向上的右手坐标系;
  2. velodyne lidar被安装为x轴向前,y轴向左,z轴向上的右手坐标系;
  3. scanRegistration会把两者通过交换坐标轴,都统一到z轴向前,x轴向左,y轴向上的右手坐标系。
    这是J. Zhang的论文里面使用的坐标系,交换后
R = Ry(yaw)*Rx(pitch)*Rz(roll)

初始化

设置扫描周期,velodyne频率10Hz,周期0.1s

const double scanPeriod = 0.1;

初始化控制变量

const int systemDelay = 20;//弃用前20帧初始数据
int systemInitCount = 0;
bool systemInited = false;

设置激光雷达线数

const int N_SCANS = 16;

设置一帧点云中点的最大数量

float cloudCurvature[40000];

点对应的序号

int cloudSortInd[40000];

点是否筛选过标志:0-未筛选过,1-筛选过

int cloudNeighborPicked[40000];

点分类标号:

  • 2 - 曲率很大
  • 1 - 曲率比较大
  • 0 - 曲率比较小
  • -1 - 曲率很小
int cloudLabel[40000];

imu时间戳的位置

int imuPointerFront = 0;

imu最新收到的点在数组中的位置

int imuPointerLast = -1;

imu循环队列长度

const int imuQueLength = 200;

点云数据开始点和当前点的欧拉角、速度、位移

float imuRollStart = 0, imuPitchStart = 0, imuYawStart = 0; // 开始点的欧拉角
float imuRollCur = 0, imuPitchCur = 0, imuYawCur = 0; // 当前点的欧拉角
float imuVeloXStart = 0, imuVeloYStart = 0, imuVeloZStart = 0; // 开始点的速度
float imuShiftXStart = 0, imuShiftYStart = 0, imuShiftZStart = 0; // 开始点的位移
float imuVeloXCur = 0, imuVeloYCur = 0, imuVeloZCur = 0; // 当前点的位移
float imuShiftXCur = 0, imuShiftYCur = 0, imuShiftZCur = 0; // 当前点的位移

每次点云数据当前点相对于开始第一个点的畸变位移,速度

float imuShiftFromStartXCur = 0, imuShiftFromStartYCur = 0, imuShiftFromStartZCur = 0;
float imuVeloFromStartXCur = 0, imuVeloFromStartYCur = 0, imuVeloFromStartZCur = 0;

IMU信息:时间、欧拉角、加速度、速度、位移

double imuTime[imuQueLength] = {0};
float imuRoll[imuQueLength] = {0};
float imuPitch[imuQueLength] = {0};
float imuYaw[imuQueLength] = {0};

float imuAccX[imuQueLength] = {0};
float imuAccY[imuQueLength] = {0};
float imuAccZ[imuQueLength] = {0};

float imuVeloX[imuQueLength] = {0};
float imuVeloY[imuQueLength] = {0};
float imuVeloZ[imuQueLength] = {0};

float imuShiftX[imuQueLength] = {0};
float imuShiftY[imuQueLength] = {0};
float imuShiftZ[imuQueLength] = {0};

ros发布消息

ros::Publisher pubLaserCloud;
ros::Publisher pubCornerPointsSharp;
ros::Publisher pubCornerPointsLessSharp;
ros::Publisher pubSurfPointsFlat;
ros::Publisher pubSurfPointsLessFlat;
ros::Publisher pubImuTrans;

位移畸变计算-ShiftToStartIMU

计算局部坐标系下点云中的点相对第一个开始点的由于加减速运动产生的位移畸变,ShiftToStartIMU()函数主要计算一帧数据中某点相对于一帧的起始点由于加减速造成的运动畸变。因此首先要求出世界坐标系下的加减速造成的运动畸变,然后将运动畸变值经过绕y、x、z轴旋转后得到起始点坐标系下的运动畸变。根据以下公式

设俯仰角α(pitch),围绕Y轴旋转的;偏航角β(yaw),围绕Z轴旋转的角度,滚转角γ(roll)围绕X轴旋转的角度。对于x,y,z三个轴的不同旋转顺序一共有(x-y-z, y-z-x, z-x-y, x-z-y, z-y-x, y-x-z)六种组合。论文和代码里写的是y-x-z。

  • 左乘: 坐标系不动,点动,则左乘。

  • 右乘: 点不动,坐标系动,则右乘。
    在这里插入图片描述

  • 世界坐标系下的畸变位移

Δ s w o r l d − s t a 2 c u r − x = s c u r − x − s s t a − x − v x Δ t \Delta s_{world-sta2cur-x}=s_{cur-x}-s_{sta-x}-v_x \Delta t Δsworldsta2curx=scurxsstaxvxΔt

Δ s w o r l d − s t a 2 c u r − y = s c u r − y − s s t a − y − v y Δ t \Delta s_{world-sta2cur-y}=s_{cur-y}-s_{sta-y}-v_y \Delta t Δsworldsta2cury=scurysstayvyΔt

Δ s w o r l d − s t a 2 c u r − z = s c u r − z − s s t a − z − v z Δ t \Delta s_{world-sta2cur-z}=s_{cur-z}-s_{sta-z}-v_z \Delta t Δsworldsta2curz=scurzsstazvzΔt

  • 绕y轴旋转
    [ x 1 y 1 z 1 ] T = [ Δ s x Δ s y Δ s z ] T R y ( β ) = [ Δ s w o r l d − x Δ s w o r l d − y Δ s w o r l d − z ] T [ c o s β 0 s i n β 0 1 0 − s i n β 0 s i n β ] \begin{bmatrix}x1\\ y1\\ z1\end{bmatrix}^T=\begin{bmatrix} \Delta s_x\\ \Delta s_y\\ \Delta s_z\end{bmatrix}^TR_y(β)=\begin{bmatrix} \Delta s_{world-x}\\ \Delta s_{world-y}\\ \Delta s_{world-z}\end{bmatrix}^T\begin{bmatrix} cosβ & 0 & sinβ\\ 0 & 1 & 0\\ -sinβ & 0 & sinβ \end{bmatrix} x1y1z1T=ΔsxΔsyΔszTRy(β)=ΔsworldxΔsworldyΔsworldzTcosβ0sinβ010sinβ0sinβ

  • 绕x轴旋转
    [ x 2 y 2 z 2 ] T = [ x 1 y 1 z 1 ] T R x ( α ) = [ x 1 y 1 z 1 ] T [ 1 0 0 0 c o s α − s i n α 0 s i n α c o s α ] \begin{bmatrix}x2\\ y2\\ z2\end{bmatrix}^T=\begin{bmatrix} x1\\ y1\\ z1\end{bmatrix}^TR_x(α)=\begin{bmatrix} x1\\ y1\\ z1\end{bmatrix}^T\begin{bmatrix} 1 & 0 & 0\\ 0 & cosα & -sinα\\ 0 & sinα& cosα \end{bmatrix} x2y2z2T=x1y1z1TRx(α)=x1y1z1T1000cosαsinα0sinαcosα

  • 绕z轴旋转
    [ Δ s l o c a l − x Δ s l o c a l − y Δ s l o c a l − z ] T = [ x 2 y 2 z 2 ] T R z ( γ ) = [ x 2 y 2 z 2 ] T [ c o s γ − s i n γ 0 s i n γ c o s γ 0 0 0 1 ] \begin{bmatrix} \Delta s_{local-x}\\ \Delta s_{local-y}\\ \Delta s_{local-z}\end{bmatrix}^T=\begin{bmatrix}x2\\ y2\\ z2\end{bmatrix}^TR_z(γ)=\begin{bmatrix}x2\\ y2\\ z2\end{bmatrix}^T\begin{bmatrix} cosγ & -sinγ & 0\\ sinγ & cosγ & 0\\ 0 & 0 & 1 \end{bmatrix} ΔslocalxΔslocalyΔslocalzT=x2y2z2TRz(γ)=x2y2z2Tcosγsinγ0sinγcosγ0001

综上,得到

  • 局部坐标系下的畸变位移

[ Δ s l o c a l − x Δ s l o c a l − y Δ s l o c a l − z ] T = [ Δ s w o r l d − s t a 2 c u r − x Δ s w o r l d − s t a 2 c u r − y Δ s w o r l d − s t a 2 c u r − z ] T R y ( β ) R x ( α ) R z ( γ ) \begin{bmatrix} \Delta s_{local-x}\\ \Delta s_{local-y}\\ \Delta s_{local-z}\end{bmatrix}^T=\begin{bmatrix} \Delta s_{world-sta2cur-x}\\ \Delta s_{world-sta2cur-y}\\ \Delta s_{world-sta2cur-z}\end{bmatrix}^TR_y(β)R_x(α)R_z(γ) ΔslocalxΔslocalyΔslocalzT=Δsworldsta2curxΔsworldsta2curyΔsworldsta2curzTRy(β)Rx(α)Rz(γ)

void ShiftToStartIMU(float pointTime)
{
  //计算相对于第一个点由于加减速产生的畸变位移(全局坐标系下畸变位移量delta_Tg)
  //imuShiftFromStartCur = imuShiftCur - (imuShiftStart + imuVeloStart * pointTime)
  imuShiftFromStartXCur = imuShiftXCur - imuShiftXStart - imuVeloXStart * pointTime;
  imuShiftFromStartYCur = imuShiftYCur - imuShiftYStart - imuVeloYStart * pointTime;
  imuShiftFromStartZCur = imuShiftZCur - imuShiftZStart - imuVeloZStart * pointTime;

  /********************************************************************************
  Rz(pitch).inverse * Rx(pitch).inverse * Ry(yaw).inverse * delta_Tg
  从全局坐标系到局部坐标系的转换
  *********************************************************************************/

  //绕y轴旋转(-imuYawStart),即Ry(yaw).inverse
  float x1 = cos(imuYawStart) * imuShiftFromStartXCur - sin(imuYawStart) * imuShiftFromStartZCur;
  float y1 = imuShiftFromStartYCur;
  float z1 = sin(imuYawStart) * imuShiftFromStartXCur + cos(imuYawStart) * imuShiftFromStartZCur;

  //绕x轴旋转(-imuPitchStart),即Rx(pitch).inverse
  float x2 = x1;
  float y2 = cos(imuPitchStart) * y1 + sin(imuPitchStart) * z1;
  float z2 = -sin(imuPitchStart) * y1 + cos(imuPitchStart) * z1;

  //绕z轴旋转(-imuRollStart),即Rz(pitch).inverse
  imuShiftFromStartXCur = cos(imuRollStart) * x2 + sin(imuRollStart) * y2;
  imuShiftFromStartYCur = -sin(imuRollStart) * x2 + cos(imuRollStart) * y2;
  imuShiftFromStartZCur = z2;
}

速度畸变计算-VeloToStartIMU

与位移畸变的计算同理,速度畸变由VeloToStartIMU()函数完成,主要求解当前点相对于起始点的速度畸变,先计算全局坐标系下速度畸变,再根据旋转矩阵求解起始点的局部坐标系中。

  • 世界坐标系下的畸变位移

Δ v w o r l d − s t a 2 c u r − x = v c u r − x − v s t a − x \Delta v_{world-sta2cur-x}=v_{cur-x}-v_{sta-x} Δvworldsta2curx=vcurxvstax

Δ v w o r l d − s t a 2 c u r − y = v c u r − y − v s t a − y \Delta v_{world-sta2cur-y}=v_{cur-y}-v_{sta-y} Δvworldsta2cury=vcuryvstay

Δ v w o r l d − s t a 2 c u r − z = v c u r − z − v s t a − z \Delta v_{world-sta2cur-z}=v_{cur-z}-v_{sta-z} Δvworldsta2curz=vcurzvstaz

  • 局部坐标系下的畸变位移

[ Δ v l o c a l − x Δ v l o c a l − y Δ v l o c a l − z ] T = [ Δ v w o r l d − s t a 2 c u r − x Δ v w o r l d − s t a 2 c u r − y Δ v w o r l d − s t a 2 c u r − z ] T R y ( β ) R x ( α ) R z ( γ ) \begin{bmatrix} \Delta v_{local-x}\\ \Delta v_{local-y}\\ \Delta v_{local-z}\end{bmatrix}^T=\begin{bmatrix} \Delta v_{world-sta2cur-x}\\ \Delta v_{world-sta2cur-y}\\ \Delta v_{world-sta2cur-z}\end{bmatrix}^TR_y(β)R_x(α)R_z(γ) ΔvlocalxΔvlocalyΔvlocalzT=Δvworldsta2curxΔvworldsta2curyΔvworldsta2curzTRy(β)Rx(α)Rz(γ)

R y ( β ) = [ c o s β 0 s i n β 0 1 0 − s i n β 0 c o s β ] R_y(β) = \begin{bmatrix} cosβ & 0 & sinβ\\ 0 & 1 & 0\\ -sinβ & 0 & cosβ \end{bmatrix} Ry(β)=cosβ0sinβ010sinβ0cosβ

R x ( α ) = [ 1 0 0 0 c o s α − s i n α 0 s i n α c o s α ] R_x(α)=\begin{bmatrix} 1 & 0 & 0\\ 0 & cosα & -sinα\\ 0 & sinα& cosα \end{bmatrix} Rx(α)=1000cosαsinα0sinαcosα

R z ( γ ) = [ c o s γ − s i n γ 0 s i n γ c o s γ 0 0 0 1 ] R_z(γ)=\begin{bmatrix} cosγ & -sinγ & 0\\ sinγ & cosγ & 0\\ 0 & 0 & 1 \end{bmatrix} Rz(γ)=cosγsinγ0sinγcosγ0001

void VeloToStartIMU()
{
  //计算相对于第一个点由于加减速产生的畸变速度(全局坐标系下畸变速度增量delta_Vg)
  imuVeloFromStartXCur = imuVeloXCur - imuVeloXStart;
  imuVeloFromStartYCur = imuVeloYCur - imuVeloYStart;
  imuVeloFromStartZCur = imuVeloZCur - imuVeloZStart;

  /********************************************************************************
    Rz(pitch).inverse * Rx(pitch).inverse * Ry(yaw).inverse * delta_Vg
    transfrom from the global frame to the local frame
  *********************************************************************************/
  
  //绕y轴旋转(-imuYawStart),即Ry(yaw).inverse
  float x1 = cos(imuYawStart) * imuVeloFromStartXCur - sin(imuYawStart) * imuVeloFromStartZCur;
  float y1 = imuVeloFromStartYCur;
  float z1 = sin(imuYawStart) * imuVeloFromStartXCur + cos(imuYawStart) * imuVeloFromStartZCur;

  //绕x轴旋转(-imuPitchStart),即Rx(pitch).inverse
  float x2 = x1;
  float y2 = cos(imuPitchStart) * y1 + sin(imuPitchStart) * z1;
  float z2 = -sin(imuPitchStart) * y1 + cos(imuPitchStart) * z1;

  //绕z轴旋转(-imuRollStart),即Rz(pitch).inverse
  imuVeloFromStartXCur = cos(imuRollStart) * x2 + sin(imuRollStart) * y2;
  imuVeloFromStartYCur = -sin(imuRollStart) * x2 + cos(imuRollStart) * y2;
  imuVeloFromStartZCur = z2;
}

去除位移畸变-TransformToStartIMU

在完成位移畸变的计算后,就可以去除点云加减速产生的位移畸变。方法还是与上同理,先将点云数据(xyz)在当前点转换到世界坐标系下,然后在从世界坐标系转换到点云起始坐标系下,最后减去加减速导致的位移值。核心思想就是借助世界坐标系来进行坐标转换。

  • 当前坐标系转换到世界坐标系

[ s w o r l d − x s w o r l d − y s w o r l d − z ] T = [ s l o c a l − c u r − x s l o c a l − c u r − y s l o c a l − c u r − z ] T R z ( γ ) − 1 R x ( α ) − 1 R y ( β ) − 1 \begin{bmatrix} s_{world-x}\\ s_{world-y}\\ s_{world-z}\end{bmatrix}^T=\begin{bmatrix} s_{local-cur-x}\\ s_{local-cur-y}\\ s_{local-cur-z}\end{bmatrix}^T R_z(γ)^{-1}R_x(α)^{-1}R_y(β)^{-1} sworldxsworldysworldzT=slocalcurxslocalcuryslocalcurzTRz(γ)1Rx(α)1Ry(β)1

R z ( γ ) − 1 = [ c o s γ s i n γ 0 − s i n γ c o s γ 0 0 0 1 ] R_z(γ)^{-1}=\begin{bmatrix} cosγ & sinγ & 0\\ -sinγ & cosγ & 0\\ 0 & 0 & 1 \end{bmatrix} Rz(γ)1=cosγsinγ0sinγcosγ0001

R x ( α ) − 1 = [ 1 0 0 0 c o s α s i n α 0 − s i n α c o s α ] R_x(α)^{-1}=\begin{bmatrix} 1 & 0 & 0\\ 0 & cosα & sinα\\ 0 & -sinα& cosα \end{bmatrix} Rx(α)1=1000cosαsinα0sinαcosα

R y ( β ) − 1 = [ c o s β 0 − s i n β 0 1 0 s i n β 0 c o s β ] R_y(β)^{-1} = \begin{bmatrix} cosβ & 0 & -sinβ\\ 0 & 1 & 0\\ sinβ & 0 & cosβ \end{bmatrix} Ry(β)1=cosβ0sinβ010sinβ0cosβ

  • 世界坐标系转换到起始坐标系,并减去位移畸变的值

[ s l o c a l − s t a − x s l o c a l − s t a − y s l o c a l − s t a − z ] T = [ s w o r l d − x s w o r l d − y s w o r l d − z ] T R y ( β ) R x ( α ) R z ( γ ) + [ Δ s w o r l d − s t a 2 c u r − x Δ s w o r l d − s t a 2 c u r − y Δ s w o r l d − s t a 2 c u r − z ] T \begin{bmatrix} s_{local-sta-x}\\ s_{local-sta-y}\\ s_{local-sta-z}\end{bmatrix}^T=\begin{bmatrix} s_{world-x}\\ s_{world-y}\\ s_{world-z}\end{bmatrix}^TR_y(β)R_x(α)R_z(γ) + \begin{bmatrix} \Delta s_{world-sta2cur-x}\\ \Delta s_{world-sta2cur-y}\\ \Delta s_{world-sta2cur-z}\end{bmatrix}^T slocalstaxslocalstayslocalstazT=sworldxsworldysworldzTRy(β)Rx(α)Rz(γ)+Δsworldsta2curxΔsworldsta2curyΔsworldsta2curzT

R y ( β ) = [ c o s β 0 s i n β 0 1 0 − s i n β 0 c o s β ] R_y(β) = \begin{bmatrix} cosβ & 0 & sinβ\\ 0 & 1 & 0\\ -sinβ & 0 & cosβ \end{bmatrix} Ry(β)=cosβ0sinβ010sinβ0cosβ

R x ( α ) = [ 1 0 0 0 c o s α − s i n α 0 s i n α c o s α ] R_x(α)=\begin{bmatrix} 1 & 0 & 0\\ 0 & cosα & -sinα\\ 0 & sinα& cosα \end{bmatrix} Rx(α)=1000cosαsinα0sinαcosα

R z ( γ ) = [ c o s γ − s i n γ 0 s i n γ c o s γ 0 0 0 1 ] R_z(γ)=\begin{bmatrix} cosγ & -sinγ & 0\\ sinγ & cosγ & 0\\ 0 & 0 & 1 \end{bmatrix} Rz(γ)=cosγsinγ0sinγcosγ0001

void TransformToStartIMU(PointType *p)
{
  /********************************************************************************
    Ry*Rx*Rz*Pl, transform point to the global frame
  *********************************************************************************/
  //绕z轴旋转(imuRollCur)
  float x1 = cos(imuRollCur) * p->x - sin(imuRollCur) * p->y;
  float y1 = sin(imuRollCur) * p->x + cos(imuRollCur) * p->y;
  float z1 = p->z;

  //绕x轴旋转(imuPitchCur)
  float x2 = x1;
  float y2 = cos(imuPitchCur) * y1 - sin(imuPitchCur) * z1;
  float z2 = sin(imuPitchCur) * y1 + cos(imuPitchCur) * z1;

  //绕y轴旋转(imuYawCur)
  float x3 = cos(imuYawCur) * x2 + sin(imuYawCur) * z2;
  float y3 = y2;
  float z3 = -sin(imuYawCur) * x2 + cos(imuYawCur) * z2;

  /********************************************************************************
    Rz(pitch).inverse * Rx(pitch).inverse * Ry(yaw).inverse * Pg
    transfrom global points to the local frame
  *********************************************************************************/
  
  //绕y轴旋转(-imuYawStart)
  float x4 = cos(imuYawStart) * x3 - sin(imuYawStart) * z3;
  float y4 = y3;
  float z4 = sin(imuYawStart) * x3 + cos(imuYawStart) * z3;

  //绕x轴旋转(-imuPitchStart)
  float x5 = x4;
  float y5 = cos(imuPitchStart) * y4 + sin(imuPitchStart) * z4;
  float z5 = -sin(imuPitchStart) * y4 + cos(imuPitchStart) * z4;

  //绕z轴旋转(-imuRollStart),然后叠加平移量
  p->x = cos(imuRollStart) * x5 + sin(imuRollStart) * y5 + imuShiftFromStartXCur;
  p->y = -sin(imuRollStart) * x5 + cos(imuRollStart) * y5 + imuShiftFromStartYCur;
  p->z = z5 + imuShiftFromStartZCur;
}

位移与速度校正-AccumulateIMUShift

积分速度与位移的功能是通过AccumulateIMUShift()函数来实现的,将当前时刻的加速度值绕ZXY轴(原XYZ而安装后变为ZXY)分别旋转(roll: γ, pitch: α, yaw: β)角,转换得到世界坐标系下的加速度值(right hand rule)。

  • 当前坐标系转换世界坐标系,并减去位移畸变的值

[ a w o r l d − x a w o r l d − y a w o r l d − z ] T = [ a l o c a l − x a l o c a l − y a l o c a l − z ] T R z ( γ ) − 1 R x ( α ) − 1 R y ( β ) − 1 \begin{bmatrix} a_{world-x}\\ a_{world-y}\\ a_{world-z}\end{bmatrix}^T=\begin{bmatrix} a_{local-x}\\ a_{local-y}\\ a_{local-z}\end{bmatrix}^T R_z(γ)^{-1}R_x(α)^{-1}R_y(β)^{-1} aworldxaworldyaworldzT=alocalxalocalyalocalzTRz(γ)1Rx(α)1Ry(β)1

R z ( γ ) − 1 = [ c o s γ s i n γ 0 − s i n γ c o s γ 0 0 0 1 ] R_z(γ)^{-1}=\begin{bmatrix} cosγ & sinγ & 0\\ -sinγ & cosγ & 0\\ 0 & 0 & 1 \end{bmatrix} Rz(γ)1=cosγsinγ0sinγcosγ0001

R x ( α ) − 1 = [ 1 0 0 0 c o s α s i n α 0 − s i n α c o s α ] R_x(α)^{-1}=\begin{bmatrix} 1 & 0 & 0\\ 0 & cosα & sinα\\ 0 & -sinα& cosα \end{bmatrix} Rx(α)1=1000cosαsinα0sinαcosα

R y ( β ) − 1 = [ c o s β 0 − s i n β 0 1 0 s i n β 0 c o s β ] R_y(β)^{-1} = \begin{bmatrix} cosβ & 0 & -sinβ\\ 0 & 1 & 0\\ sinβ & 0 & cosβ \end{bmatrix} Ry(β)1=cosβ0sinβ010sinβ0cosβ

  • 上一个Imu点到当前点所经历时间

Δ t = t l a s t − t b a c k \Delta t_{} = t_{last}-t_{back} Δt=tlasttback

  • imu频率比lidar高才进行校正,分别是位移校正和速度校正

s l a s t − x = s b a c k − x + v b a c k − x Δ t + 1 2 a b a c k − x Δ t 2 s l a s t − y = s b a c k − y + v b a c k − y Δ t + 1 2 a b a c k − y Δ t 2 s l a s t − z = s b a c k − z + v b a c k − z Δ t + 1 2 a b a c k − z Δ t 2 s_{last-x} = s_{back-x} + v_{back-x}\Delta t_{} + \frac{1}{2} a_{back-x}\Delta t_{}^2 \\ s_{last-y} = s_{back-y} + v_{back-y}\Delta t_{} + \frac{1}{2} a_{back-y}\Delta t_{}^2 \\ s_{last-z} = s_{back-z} + v_{back-z}\Delta t_{} + \frac{1}{2} a_{back-z}\Delta t_{}^2 slastx=sbackx+vbackxΔt+21abackxΔt2slasty=sbacky+vbackyΔt+21abackyΔt2slastz=sbackz+vbackzΔt+21abackzΔt2

v l a s t − x = v b a c k − x + a b a c k − x Δ t v l a s t − y = v b a c k − y + a b a c k − y Δ t v l a s t − z = v b a c k − z + a b a c k − z Δ t v_{last-x} = v_{back-x} + a_{back-x}\Delta t_{} \\ v_{last-y} = v_{back-y} + a_{back-y}\Delta t_{} \\ v_{last-z} = v_{back-z} + a_{back-z}\Delta t_{} vlastx=vbackx+abackxΔtvlasty=vbacky+abackyΔtvlastz=vbackz+abackzΔt

void AccumulateIMUShift()
{
  float roll = imuRoll[imuPointerLast];
  float pitch = imuPitch[imuPointerLast];
  float yaw = imuYaw[imuPointerLast];
  float accX = imuAccX[imuPointerLast];
  float accY = imuAccY[imuPointerLast];
  float accZ = imuAccZ[imuPointerLast];

  //将当前时刻的加速度值绕交换过的ZXY固定轴(原XYZ)分别旋转(roll, pitch, yaw)角,转换得到世界坐标系下的加速度值(right hand rule)
  //绕z轴旋转(roll)
  float x1 = cos(roll) * accX - sin(roll) * accY;
  float y1 = sin(roll) * accX + cos(roll) * accY;
  float z1 = accZ;
  //绕x轴旋转(pitch)
  float x2 = x1;
  float y2 = cos(pitch) * y1 - sin(pitch) * z1;
  float z2 = sin(pitch) * y1 + cos(pitch) * z1;
  //绕y轴旋转(yaw)
  accX = cos(yaw) * x2 + sin(yaw) * z2;
  accY = y2;
  accZ = -sin(yaw) * x2 + cos(yaw) * z2;

  //上一个imu点
  int imuPointerBack = (imuPointerLast + imuQueLength - 1) % imuQueLength;
  //上一个点到当前点所经历的时间,即计算imu测量周期
  double timeDiff = imuTime[imuPointerLast] - imuTime[imuPointerBack];
  //要求imu的频率至少比lidar高,这样的imu信息才使用,后面校正也才有意义
  if (timeDiff < scanPeriod) {//(隐含从静止开始运动)
    //求每个imu时间点的位移与速度,两点之间视为匀加速直线运动
    imuShiftX[imuPointerLast] = imuShiftX[imuPointerBack] + imuVeloX[imuPointerBack] * timeDiff 
                              + accX * timeDiff * timeDiff / 2;
    imuShiftY[imuPointerLast] = imuShiftY[imuPointerBack] + imuVeloY[imuPointerBack] * timeDiff 
                              + accY * timeDiff * timeDiff / 2;
    imuShiftZ[imuPointerLast] = imuShiftZ[imuPointerBack] + imuVeloZ[imuPointerBack] * timeDiff 
                              + accZ * timeDiff * timeDiff / 2;

    imuVeloX[imuPointerLast] = imuVeloX[imuPointerBack] + accX * timeDiff;
    imuVeloY[imuPointerLast] = imuVeloY[imuPointerBack] + accY * timeDiff;
    imuVeloZ[imuPointerLast] = imuVeloZ[imuPointerBack] + accZ * timeDiff;
  }
}

接收点云数据-laserCloudHandler

我看了一下这个函数,很长,这一章估计写不完了,留到下一章吧。

结语

如果你看到这里,说明你已经下定决心要学习loam了,学习新知识的过程总是痛苦的,与君共勉吧!

  • 4
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值