【学习笔记】LIO-SAM代码学习

一、LIO-SAM系统总览

在这里插入图片描述

两个因子图:
We design a system that maintains two graphs and runs up to 10x faster than real-time.

The factor graph in “mapOptimization.cpp” optimizes lidar odometry factor and GPS factor. This factor graph is maintained consistently throughout the whole test.
The factor graph in “imuPreintegration.cpp” optimizes IMU and lidar odometry factor and estimates IMU bias. This factor graph is reset periodically and guarantees real-time odometry estimation at IMU frequency.

基本信息

github代码
github注释代码

二、LIO-SAM前端源码分析

2.1 GTSAM关于IMU预积分相关接口介绍

通过IMU预积分相关介绍可知,我们对两个关键帧之间的若干帧IMU进行预积分,以形成预积分约束,对两帧之间的位置、速度、姿态以及零偏进行约束。

GTSAM从4.0版本开始就在内部增加了IMU预积分相关的接口,因此,为了实现把预积分因子加入到图优化框架中,我们有必要熟悉一下GTSAM中跟IMU预积分相关的接口
定义:

预积分相关参数,我们对IMU数据进行预积分之前通常需要事先知道IMU的噪声,重力方向等参数。

gtsam: :PreintegrationParams

LIO-SAM中PreintegrationParams调用了MakeSharedU;MakeSharedU中重力加速度方向分为Z轴向上和向下两种;NED:North-East-Down坐标系(右手法则),同理ENU;
在这里插入图片描述
在这里插入图片描述

gtsam: :PreintegratedImuMeasurements

跟预积分相关的计算就在这个类中实现
这个类有一些重要的接口

(1) resetIntegrationAndSetBias

将预积分量复位,也就是说清空刚刚的预积分量,重新开始一个新的预积分量,因为预积分的计算依赖一个初始的IMU零偏,因此,在复位之后需要输入零偏值,
所以这里复位和重设零偏在一个接口里。

(2) integrateMeasurement

输入IMU的测量值,其内部会自动实现预积分量的更新以及协方差矩阵的更新

(3) deltaTij

预积分量跨越的时间长度

(4) predict

预积分量可以计算出两帧之间的相对位置、速度、姿态的变化量,那结合上一帧的状态量就可以计算出下一关键帧根据预积分结果的推算值。

2.2 IMU预积分前端(imuPreintegration.cpp)

src分为四个.cpp文件,每个文件都是一个独立的ros节点(每个ros节点是一个独立的进程,有main函数):featureExtraction.cpp,imageProjection.cpp,imuPreintegration.cpp,map Optimization.cpp
include包含的utility为传感器数据处理;

mapOptimization优化的过程中发送两个位姿:(后会详细介绍)

  • 当前帧和前一帧获得的一个增量(increments)-> 提供给imuPreintegration,并且最新的imu和最新的lidar帧之间的增量补偿回环检测之后的位姿
  • 被回环检测之后的位姿 (全局一致状态)

在这里插入图片描述

TransformFusion类
功能简介:
主要功能是订阅激光里程计(来自MapOptimization)和IMU里程计,根据前一时刻激光里程计,和该时刻到当前时刻的IMU里程计变换增量,计算当前时刻IMU里程计;rviz展示IMU里程计轨迹(局部)。
订阅:
1、lio_sam/mapping/odometry:订阅激光里程计,来自MapOptimization;
2、odomTopic+“_incremental”:订阅imu里程计,来自ImuPreintegration。
发布:
1、odomTopic:发布IMU里程计,用于rviz展示;
2、lio_sam/imu/path:发布IMU里程计轨迹,仅展示最近一帧激光里程计时刻到当前时刻之间的轨迹。

IMUPreintegration类
功能简介:
1、用激光里程计,两帧激光里程计之间的IMU预积分量构建因子图,优化当前帧的状态(包括位姿、速度、偏置);
2、以优化后的状态为基础,施加IMU预积分量,得到每一时刻的IMU里程计。
订阅:
1、imuTopic:订阅IMU原始数据,以因子图优化后的激光里程计为基础,施加两帧之间的IMU预计分量,预测每一时刻(IMU频率)的IMU里程计;
2、lio_sam/mapping/odometry_incremental:订阅激光里程计(来自MapOptimization),用两帧之间的IMU预积分量构建因子图,优化当前帧位姿(这个位姿仅用于更新每时刻的IMU里程计,以及下一次因子图优化)。
发布:
1、odomTopic+“_incremental”:发布IMU里程计;

int main(int argc, char** argv)
{
    ros::init(argc, argv, "roboat_loam");	// ros初始化
    
    IMUPreintegration ImuP;	// 定义ImuP类

    TransformFusion TF;	// 定义TF类

    ROS_INFO("\033[1;32m----> IMU Preintegration Started.\033[0m");	// 打印消息
    
    ros::MultiThreadedSpinner spinner(4);	// 多线程触发,开辟四个线程进行回调,提升速度
    spinner.spin();	// 程序停留等待回调函数执行
    
    return 0;
}

该模块涉及到的变量结点

gtsam::Pose3 //表示六自由度位姿
gtsam::Vector3 //表示三自由度速度
gtsam::imuBias: :ConstantBias //表示IMU零偏

以上也是预积分模型中涉及到的三种状态变量
涉及到的因子结点:

gtsam: :PriorFactor<T>

先验因子,表示对某个状态量T的一个先验估计,约束某个状态变量的状态不会离该先验值过远

gtsam::ImuFactor

imu因子,通过IMU预积分量构造出IMU因子,即IMU约束

gtsam::BetweenFactor

状态量间的约束,约束相邻两状态量之间的差值不会距离该约束过远

在这里插入图片描述
【对此处的理解】:
如下图所示,imu频率大于odom频率;我们希望以imu频率发布位姿。如果发布90s处的实时性较差,为此,我们发布还未处理的99s位姿,依据黑点处90s的最佳位姿对当前的imu数据进行推算。
在这里插入图片描述

2.3 点云预处理前端(imageProjection.cpp,FeatureExtraction.cpp)

imageProjection需要注意的点:

  1. ring即哪一根scan(哪一根扫描线)
  2. 点云去畸变使用了简单的运动补偿方式,只要旋转的补偿即可,平移补偿不做影响不大;kitti比较理想(已经补偿好);

imageProjection类
功能简介:
1、利用当前激光帧起止时刻间的imu数据计算旋转增量,IMU里程计数据(来自ImuPreintegration)计算平移增量,进而对该帧激光每一时刻的激光点进行运动畸变校正(利用相对于激光帧起始时刻的位姿增量,变换当前激光点到起始时刻激光点的坐标系下,实现校正);
2、同时用IMU数据的姿态角(RPY,roll、pitch、yaw)、IMU里程计数据的的位姿,对当前帧激光位姿进行粗略初始化。
订阅:
1、imuTopic:订阅原始IMU数据;
2、odomTopic+“_incremental”:订阅IMU里程计数据,来自ImuPreintegration,表示每一时刻对应的位姿;
3、pointCloudTopic:订阅原始激光点云数据。
发布:
1、lio_sam/deskew/cloud_deskewed:发布当前帧激光运动畸变校正之后的有效点云,用于rviz展示;
2、lio_sam/deskew/cloud_info:发布当前帧激光运动畸变校正之后的点云信息,包括点云数据、初始位姿、姿态角、有效点云数据等,发布给FeatureExtraction进行特征提取。

FeatureExtraction需要注意的点:

  1. FeatureExtraction.cpp中与A-LOAM特征提取基本一致,就是没有和A-LOAM一样区分明显和一般的面点/角点;

FeatureExtraction类
功能简介:
对经过运动畸变校正之后的当前帧激光点云,计算每个点的曲率,进而提取角点、平面点(用曲率的大小进行判定)。
订阅:
1、lio_sam/deskew/cloud_info:订阅当前激光帧运动畸变校正后的点云信息,来自ImageProjection。
发布:
1、lio_sam/feature/cloud_info:发布当前激光帧提取特征之后的点云信息,包括的历史数据有:运动畸变校正,点云数据,初始位姿,姿态角,有效点云数据,角点点云,平面点点云等,发布给MapOptimization;
2、lio_sam/feature/cloud_corner:发布当前激光帧提取的角点点云,用于rviz展示;
3、lio_sam/feature/cloud_surface:发布当前激光帧提取的平面点点云,用于rviz展示。

 /**
     * 当前激光帧角点寻找局部map匹配点;边缘点的优化
     * 1、更新当前帧位姿,将当前帧角点坐标变换到map系下,在局部map中查找5个最近点,距离小于1m,且5个点构成直线(用距离中心点的协方差矩阵,特征值进行判断),则认为匹配上了
     * 2、计算当前帧角点到直线的距离、垂线的单位向量,存储为角点参数
 */
    void cornerOptimization()
    {
        // 更新当前帧位姿
        updatePointAssociateToMap();

        // 使用openmp并行加速(如果每个循环都是相互独立的就可以使用)
        #pragma omp parallel for num_threads(numberOfCores)
        // 遍历当前帧角点集合
        for (int i = 0; i < laserCloudCornerLastDSNum; i++)
        {
            PointType pointOri, pointSel, coeff;    // pointSel 搜索点;pointSearchInd 找到的5个点的索引;pointSearchsqDis 5个点的距离(pcl自动从小到大排序);
            std::vector<int> pointSearchInd;
            std::vector<float> pointSearchSqDis;

            // 角点(坐标还是lidar系)
            pointOri = laserCloudCornerLastDS->points[i];
            // 根据当前帧位姿,变换到世界坐标系(map系)下
            pointAssociateToMap(&pointOri, &pointSel);
            // 在局部角点map中查找当前角点相邻的5个角点
            kdtreeCornerFromMap->nearestKSearch(pointSel, 5, pointSearchInd, pointSearchSqDis); 

            cv::Mat matA1(3, 3, CV_32F, cv::Scalar::all(0));
            cv::Mat matD1(1, 3, CV_32F, cv::Scalar::all(0));
            cv::Mat matV1(3, 3, CV_32F, cv::Scalar::all(0));
            
            // 要求距离都小于1m;计算找到的点中距离当前点最远的点,如果距离太大说明这个约束不可信,就跳过
            if (pointSearchSqDis[4] < 1.0) {
                // 计算5个点的均值坐标,记为中心点
                float cx = 0, cy = 0, cz = 0;
                for (int j = 0; j < 5; j++) {
                    cx += laserCloudCornerFromMapDS->points[pointSearchInd[j]].x;
                    cy += laserCloudCornerFromMapDS->points[pointSearchInd[j]].y;
                    cz += laserCloudCornerFromMapDS->points[pointSearchInd[j]].z;
                 }
                cx /= 5; cy /= 5;  cz /= 5;

                // 计算协方差
                float a11 = 0, a12 = 0, a13 = 0, a22 = 0, a23 = 0, a33 = 0;
                for (int j = 0; j < 5; j++) {
                    // 计算点与中心点之间的距离
                    float ax = laserCloudCornerFromMapDS->points[pointSearchInd[j]].x - cx;
                    float ay = laserCloudCornerFromMapDS->points[pointSearchInd[j]].y - cy;
                    float az = laserCloudCornerFromMapDS->points[pointSearchInd[j]].z - cz;

                    a11 += ax * ax; a12 += ax * ay; a13 += ax * az;
                    a22 += ay * ay; a23 += ay * az;
                    a33 += az * az;
                }
                a11 /= 5; a12 /= 5; a13 /= 5; a22 /= 5; a23 /= 5; a33 /= 5;

                // 构建协方差矩阵(是个对称的)
                matA1.at<float>(0, 0) = a11; matA1.at<float>(0, 1) = a12; matA1.at<float>(0, 2) = a13;
                matA1.at<float>(1, 0) = a12; matA1.at<float>(1, 1) = a22; matA1.at<float>(1, 2) = a23;
                matA1.at<float>(2, 0) = a13; matA1.at<float>(2, 1) = a23; matA1.at<float>(2, 2) = a33;

                // 特征值分解(证明这些边缘点是不是直线)
                cv::eigen(matA1, matD1, matV1); // matD1:matA1的线特征值;matV1:matA1的线特征向量

                // 如果最大的特征值相比次大特征值,大3背,认为构成了线,角点是合格的
                 if (matD1.at<float>(0, 0) > 3 * matD1.at<float>(0, 1)) {
                    // 当前帧角点坐标(map系下)
                    float x0 = pointSel.x;
                    float y0 = pointSel.y;
                    float z0 = pointSel.z;
                    // 局部map对应中心角点,沿着特征向量(直线方向)方向,前后各取一个点
                    // 特征向量对应的就是直线的方向向量;通过点的均值往两边拓展,构成一个线的两个端点
                    // matV1.at<float>(0, 0)即最大特征值matD1.at<float>(0, 0)对应的特征向量
                    float x1 = cx + 0.1 * matV1.at<float>(0, 0);
                    float y1 = cy + 0.1 * matV1.at<float>(0, 1);
                    float z1 = cz + 0.1 * matV1.at<float>(0, 2);
                    float x2 = cx - 0.1 * matV1.at<float>(0, 0);
                    float y2 = cy - 0.1 * matV1.at<float>(0, 1);
                    float z2 = cz - 0.1 * matV1.at<float>(0, 2);
                    
                    // 下面是计算点到线的残差和垂线方向(即雅克比方向,梯度下降方向)
                    // area_012,也就是三个点组成的三角形面积*2,叉积的模|axb|=a*b*sin(theta)
                    float a012 = sqrt(((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1)) * ((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1)) 
                                    + ((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1)) * ((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1)) 
                                    + ((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1)) * ((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1)));
                    
                    // line_12,底边边长
                    float l12 = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) + (z1 - z2)*(z1 - z2));
                    
                    // 两次叉积,得到点到直线的垂线段单位向量,x分量,下面同理
                    float la = ((y1 - y2)*((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1)) 
                              + (z1 - z2)*((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1))) / a012 / l12;

                    float lb = -((x1 - x2)*((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1)) 
                               - (z1 - z2)*((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1))) / a012 / l12;

                    float lc = -((x1 - x2)*((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1)) 
                               + (y1 - y2)*((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1))) / a012 / l12;

                    // 三角形的高,也就是点到直线距离
                    float ld2 = a012 / l12;

                    // 一个简单的核函数,(残差)距离越大,s越小,是个距离惩罚因子(权重)
                    float s = 1 - 0.9 * fabs(ld2);

                    // 点到直线的垂线段单位向量
                    coeff.x = s * la;
                    coeff.y = s * lb;
                    coeff.z = s * lc;
                    // 点到直线距离
                    coeff.intensity = s * ld2;
                    // 如果残差小于10cm,就认为是一个有效的约束
                    if (s > 0.1) {
                        // 当前激光帧角点,加入匹配集合中
                        laserCloudOriCornerVec[i] = pointOri;
                        // 角点的参数
                        coeffSelCornerVec[i] = coeff;
                        laserCloudOriCornerFlag[i] = true;
                    }
                }
            }
        }
    }

在这里插入图片描述
雅可比方向待学习

2.4 回环检测及位姿计算

在这里插入图片描述
在回环检测中使用,ICP进行点云配准
在这里插入图片描述

2.5 后端里程计、回环、GPS融合

MapOptimization类需要注意的点
GPS没有利用z轴的值,使用的是odom的z轴;
lidar容易产生z轴上的漂移,并且lio_sam的约束都是平面约束;
lio_sam对GPS的使用整体还是比较谨慎,是为了不会对当前里程计的平滑性产生负面影响(抖动),又引入了全局观测;

MapOptimization类
功能简介:
1、scan-to-map匹配:提取当前激光帧特征点(角点、平面点),局部关键帧map的特征点,执行scan-to-map迭代优化,更新当前帧位姿;
2、关键帧因子图优化:关键帧加入因子图,添加激光里程计因子、GPS因子、闭环因子,执行因子图优化,更新所有关键帧位姿;
3、闭环检测:在历史关键帧中找距离相近,时间相隔较远的帧设为匹配帧,匹配帧周围提取局部关键帧map,同样执行scan-to-map匹配,得到位姿变换,构建闭环因子数据,加入因子图优化。
订阅:
1、lio_sam/feature/cloud_info:订阅当前激光帧点云信息,来自FeatureExtraction;
2、gpsTopic:订阅GPS里程计;
3、lio_loop/loop_closure_detection:订阅来自外部闭环检测程序提供的闭环数据,本程序没有提供,这里实际没用上。
发布:
1、lio_sam/mapping/trajectory:发布历史关键帧里程计;
2、lio_sam/mapping/map_global:发布局部关键帧map的特征点云;
3、lio_sam/mapping/odometry:发布激光里程计,rviz中表现为坐标轴;
4、lio_sam/mapping/odometry_incremental:发布激光里程计;
5、lio_sam/mapping/path:发布激光里程计路径,rviz中表现为载体的运行轨迹;
6、lio_sam/save_map:发布地图保存服务;
7、lio_sam/mapping/icp_loop_closure_history_cloud:发布闭环匹配关键帧局部map;
8、lio_sam/mapping/icp_loop_closure_corrected_cloud:发布当前关键帧经过闭环优化后的位姿变换之后的特征点云;
9、lio_sam/mapping/loop_closure_constraints:发布闭环边,rviz中表现为闭环帧之间的连线;
10、lio_sam/mapping/map_local:发布局部map的降采样平面点集合;
11、lio_sam/mapping/cloud_registered:发布历史帧(累加的)的角点、平面点降采样集合;
12、lio_sam/mapping/cloud_registered_raw:发布当前帧原始点云配准之后的点云。

三、多传感器融合工程实践经验与技巧

3.1 A-LOAM LeGO-LOAM LIO-SAM不同算法的对比

A-LOAM(LOAM)也即原始LOAM,后续无论是LeGO-LOAM还是LIO-SAM都是基于LOAM做的改进版本,在LOAM中,作者根据多线激光雷达的性质,提出了激光雷达的线特征和面特征的提取,并以此为基础实现了一个高频率低精度的前端以及低频率高精度的后端,这一点和PTAM以来的视觉slam将tracking和mapping分为两个线程有异曲同工之妙,借此完成了一个高精度的里程计和建图功能。

LeGO-LOAM在LOAM的基础上进行了一些改进:

  1. 利用车载激光大多水平安装的特征,提取出地面点
  2. 使用聚类算法(广度优先遍历),使得前端特征更为干净
  3. 前端使用两步优化方法(先对roll,pitch,z;再yaw,x,y),减少运算负载,使其在嵌入式平台上也能运行
  4. 后端引入关键帧概念,同时加入了回环检测

LIO-SAM在上述基础上的改进:

  1. 由于其支持手持设备,因此没有对地面点进行特殊处理
  2. 紧耦合的lidar+IMU融合模块, 使得其充分利用IMU的数据,对快速旋转等场景有着更好的鲁棒性
  3. 融合GPS,使得全局地图可以在没有回环的情况下有着更好的全局一致性
  4. 易于扩展的框架,方便我们将其他传感器融合进来
    总体来说,这三种框架随着时间顺序都是在前有基础进行的改造,因此,都是在吸收现在框架基础上进行的改进

3.2 算法中工程化技巧总结

在上述一些框架中,我们可以看到一些工程话的技巧,比如

  1. LeGQ-LOAM前端, 对地面点的提取,利用地面点的一些性质对roll, pitch以及z进行一 些约束和优化
  2. 通过BFS算法对前端特征进行过滤,使得更干净的特征留存了下来
  3. 后端滑动窗口的引入,使得构建局部地图更加方便,也更加方便实现纯里程记功能
  4. 对GPS的融合的谨慎的使用方式,使得既引入了全局观测,又不会对当前里程计的平滑性产生负面影响

3.3 多传感器融合算法改进落地建议

多传感器融合的目的是取长补短,比如在以激光雷达为主的融合方案中,我们需要明确激光雷达有什么缺陷,以此确定使用什么传感器进行融合

  1. 激光雷达需要运动补偿,我们需要短期内可靠的运动观测源,IMU以及轮速就可以被充分利用
  2. 激光雷达匹配本质,上是一个优化问题,需要提供-个很好的初始值,和1一样,也是需要可靠的短期运动观测源,紧耦合的IMU融合或者轮速也是非常好的处理
    方式
  3. 激光雷达频率不高,为了提高频率,我们需要高频的其他传感器以获得高频输出,此时IMU和轮速又可以成为备选
  4. 里程计会有累计漂移的问题,全局观测是解决里程记该问题的非常好的方式,GPS作为常见的全局定位传感器,提供了修正累计漂移的功能等等

3.4 多传感器融合未来发展趋势

人类需要多个传感器(眼睛、鼻子、耳朵等)来处理信息,SLAM也是一样,对传感器的正确使用会使得整个系统的鲁棒性越强,因此,在未来一段时间内,我们会尝试将更多新的传感器应用到SLAM中来,比如最近几年推出的LIVOX激光雷达等,和现有传感器一起取长补短, 来提升整体性能的鲁棒性。

同时基于已有的传感器组合,我们也会探索更多紧耦合的融合方式,使得传感器之间的融合更有效率,做出精度更高的SLAM系统。

四、SC-LIO-SAM

Light-weight: a single header and cpp file named “Scancontext.h” and “Scancontext.cpp”

  • Our module has KDtree and we used nanoflann. nanoflann is an also single-header-program and that file is in our directory.

Easy to use: A user just remembers and uses only two API functions; makeAndSaveScancontextAndKeys and detectLoopClosureID.

Fast: A single loop detection requires under 30 ms (for 20 x 60 size, 3 candidates)

4.1 Notes

4.1.1 About performance

  • 我们使用了两种类型的回环检测(即基于半径搜索(RS)的,如在最初的LIO-SAM中已经实现的,以及Scan context(SC)-based global revisit detection)。详见mapOptmization.cpp。
    performSCLoopClosure适合于纠正大的漂移,performRSLoopClosure适合于精细缝合。
  • 为了防止错误的地图修正,我们使用了Cauchy(但也可以使用DCS)内核的回环因子。详见mapOptmization.cpp。我们发现,Cauchy在本质上是足够的。

4.1.2 Minor

  • 我们在Scancontext.cpp中使用了C++14的std::make_unique,但你也可以使用C++11,只需稍微修改这一部分。
  • 我们使用了一个较大的速度上界值(见imuPreintegration.cpp中的failationDetection),用于MulRan数据集汽车平台的快速运动。
  • 一些代码行适用于Ouster LiDAR。因此,如果你使用其他的LiDAR,请参考原作者的指南并修正一些行。
  • MulRan数据集的LiDAR扫描没有ring信息,因此我们只是在imageProjection.cpp中做了一个硬编码,如int rowIdn = (i % 64) + 1,以产生LIO-SAM需要的ring index信息,并且它是有效的。但是,如果你使用其他的LiDAR,你需要改变这一行。

4.2 Aplications

  • 通过我们的保存工具,我们可以保存一组关键帧的时间、估计姿势、相应的点云和扫描上下文描述符。估计的姿势被保存为一个名为optimized_poses.txt的文件,其格式等同于著名的KITTI odometry数据集的pose.txt文件。比如说。

在这里插入图片描述

  • 如果您使用上述保存的文件,您可以将这些数据反馈给Removert,可以删除动态对象。不需要GT标签或外部传感器数据,如RTK-GPS。本教程指导了从运行SC-LIO-SAM到保存数据到Removert的步骤,以删除扫描中的动态物体。示例结果是。

在这里插入图片描述

  • 为了安全和轻量级的地图保存,我们支持离线扫描合并工具,用于在用户的ROI内构建全局地图(见tools/python/makeMergedMap.py,详情请见教程视频)。
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
lio-sam是一个开源项目,是LIO(Linux内核iSCSI target)模块的一个分支。它是专门为高性能和可扩展性而设计的iSCSI目标代码lio-sam项目的主要目标是提供一个高性能的iSCSI目标,同时保持Linux kernel的稳定性和可靠性。它在传输层使用Scst(SCSI target实现)和LIO(Linux iSCSI实现)的组合,并有一些优化以提高性能。它还支持各种iSCSI功能,如CHAP认证、数据压缩和IPsec等。 代码阅读lio-sam对Linux内核和iSCSI有一定的了解是很有帮助的。lio-sam使用了一些Linux内核的机制,如工作队列和内存管理。了解这些机制将有助于理解lio-sam的实现原理和性能优化技巧。 在阅读lio-sam代码时,可以关注以下几个方面: 1. LIO模块的初始化和配置:lio-sam在加载模块时进行一些初始化工作,包括创建Scst的实例和配置iSCSI target。了解这些步骤可以帮助理解lio-sam的工作流程和配置方式。 2. iSCSI连接管理:lio-sam负责管理iSCSI连接,包括连接的建立、维护和中断。了解连接管理的实现原理可以帮助理解lio-sam如何处理多个客户端的连接和请求。 3. SCSI命令处理:lio-sam的核心功能是处理SCSI命令。了解lio-sam如何解析SCSI命令、调用底层存储设备和返回响应可以帮助理解其工作原理和性能优化方法。 4. 性能优化技巧:lio-sam的设计目标之一是提高性能。代码中可能包含一些性能优化技巧,如批量处理、IO调度和缓存管理等。了解这些技巧可以帮助优化自己的应用程序。 需要注意的是,代码阅读是一项耗时耗力的工作,需要具备一定的编程和系统知识。在阅读代码时,可以结合官方文档、论坛和社区来获取更多的信息和帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值