ORB-SLAM2 --- LocalMapping::Run 局部建图线程解析

news2024/11/29 1:30:44

目录

一、线程作用

二、局部建图线程主要流程 

三、局部建图线程主函数 

四、调用函数解析

4.1 设置"允许接受关键帧"的状态标志LocalMapping::SetAcceptKeyFrames函数解析

4.2  查看列表中是否有等待被插入的关键帧LocalMapping::CheckNewKeyFrames函数

4.3 处理列表中的关键帧,包括计算BoW、更新观测、描述子、共视图,插入到地图等LocalMapping::ProcessNewKeyFrame 

4.3.1 函数最终目的

4.3.1 函数解析 

4.4 根据地图点的观测情况剔除质量不好的地图点LocalMapping::MapPointCulling

4.4.1 函数解析

4.5当前关键帧与相邻关键帧通过三角化产生新的地图点,使得跟踪更稳 LocalMapping::CreateNewMapPoints

4.5.1 函数解析

4.6 若已经处理完队列中的最后的一个关键帧,检查并融合当前关键帧与相邻关键帧帧(两级相邻)中重复的地图点LocalMapping::SearchInNeighbors 

4.6.1 函数解析

4.7 检测并剔除当前帧相邻的关键帧中冗余的关键帧LocalMapping::KeyFrameCulling 

4.7.1 函数解析

4.8 将当前帧加入到闭环检测队列中 

4.9 当要终止当前线程的时候

4.10 等待处理的关键帧列表为空且还没终止当前线程的时候的操作


一、线程作用

        处理追踪线程传来的关键帧,剔除质量不好的地图点、新增观测地图点、去除冗余关键帧,为回环检测线程传送关键帧。

二、局部建图线程主要流程 

Step 1 告诉Tracking,LocalMapping正处于繁忙状态,请不要给我发送关键帧打扰我

Step 2 处理列表中的关键帧,包括计算BoW、更新观测、描述子、共视图,插入到地图等

Step 3 根据地图点的观测情况剔除质量不好的地图点

Step 4 当前关键帧与相邻关键帧通过三角化产生新的地图点,使得跟踪更稳

Step 5 检查并融合当前关键帧与相邻关键帧帧(两级相邻)中重复的地图点

Step 6 当局部地图中的关键帧大于2个的时候进行局部地图的BA

Step 7 检测并剔除当前帧相邻的关键帧中冗余的关键帧

Step 8 将当前帧加入到闭环检测队列中

三、局部建图线程主函数 

// 线程主函数
void LocalMapping::Run()
{

    // 标记状态,表示当前run函数正在运行,尚未结束
    mbFinished = false;
    // 主循环
    while(1)
    {
        // Tracking will see that Local Mapping is busy
        // Step 1 告诉Tracking,LocalMapping正处于繁忙状态,请不要给我发送关键帧打扰我
        // LocalMapping线程处理的关键帧都是Tracking线程发来的
        SetAcceptKeyFrames(false);

        // Check if there are keyframes in the queue
        // 等待处理的关键帧列表不为空
        if(CheckNewKeyFrames())
        {
            // BoW conversion and insertion in Map
            // Step 2 处理列表中的关键帧,包括计算BoW、更新观测、描述子、共视图,插入到地图等
            ProcessNewKeyFrame();

            // Check recent MapPoints
            // Step 3 根据地图点的观测情况剔除质量不好的地图点
            MapPointCulling();

            // Triangulate new MapPoints
            // Step 4 当前关键帧与相邻关键帧通过三角化产生新的地图点,使得跟踪更稳
            CreateNewMapPoints();

            // 已经处理完队列中的最后的一个关键帧
            if(!CheckNewKeyFrames())
            {
                // Find more matches in neighbor keyframes and fuse point duplications
                //  Step 5 检查并融合当前关键帧与相邻关键帧帧(两级相邻)中重复的地图点
                SearchInNeighbors();
            }

            // 终止BA的标志
            mbAbortBA = false;

            // 已经处理完队列中的最后的一个关键帧,并且闭环检测没有请求停止LocalMapping
            if(!CheckNewKeyFrames() && !stopRequested())
            {
                // Local BA
                // Step 6 当局部地图中的关键帧大于2个的时候进行局部地图的BA
                if(mpMap->KeyFramesInMap()>2)
                    // 注意这里的第二个参数是按地址传递的,当这里的 mbAbortBA 状态发生变化时,能够及时执行/停止BA
                    Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame,&mbAbortBA, mpMap);

                // Check redundant local Keyframes
                // Step 7 检测并剔除当前帧相邻的关键帧中冗余的关键帧
                // 冗余的判定:该关键帧的90%的地图点可以被其它关键帧观测到
                KeyFrameCulling();
            }

            // Step 8 将当前帧加入到闭环检测队列中
            // 注意这里的关键帧被设置成为了bad的情况,这个需要注意
            mpLoopCloser->InsertKeyFrame(mpCurrentKeyFrame);
        }
        else if(Stop())     // 当要终止当前线程的时候
        {
            // Safe area to stop
            while(isStopped() && !CheckFinish())
            {
                // 如果还没有结束利索,那么等
                // usleep(3000);
                std::this_thread::sleep_for(std::chrono::milliseconds(3));
            }
            // 然后确定终止了就跳出这个线程的主循环
            if(CheckFinish())
                break;
        }

        // 查看是否有复位线程的请求
        ResetIfRequested();

        // Tracking will see that Local Mapping is not busy
        SetAcceptKeyFrames(true);

        // 如果当前线程已经结束了就跳出主循环
        if(CheckFinish())
            break;

        //usleep(3000);
        std::this_thread::sleep_for(std::chrono::milliseconds(3));

    }

    // 设置线程已经终止
    SetFinish();
}

        跟踪线程确定为关键帧的帧会一帧一帧的传入局部建图线程,当一帧进入局部建图线程时,我们先将局部建图线程的状态mbFinished置为false,即局部建图线程未完成。

四、调用函数解析

4.1 设置"允许接受关键帧"的状态标志LocalMapping::SetAcceptKeyFrames函数解析

// 设置"允许接受关键帧"的状态标志
void LocalMapping::SetAcceptKeyFrames(bool flag)
{
    unique_lock<mutex> lock(mMutexAccept);
    mbAcceptKeyFrames=flag;
}

        由于追踪线程和局部建图线程是同步进行的,因此需要一帧一帧进行,即当一帧传入追踪线程时,追踪线程计算位姿,计算完一帧的位姿后,将该关键帧送入局部建图线程,但这存在一个一次送多了这种情况,因为同一时间一进程只能处理一帧。

        因此当局部建图线程传入一帧后,将设置"允许接受关键帧"的状态标志设置为false,表示局部建图线程已经有关键帧进行处理,请等我处理完,我会告诉你处理完了,再给我下一帧。这个函数起到了防止局部建图线程帧累计堆叠的现象。

4.2  查看列表中是否有等待被插入的关键帧LocalMapping::CheckNewKeyFrames函数

        Tracking线程向LocalMapping中插入关键帧是先插入到该队列中。

std::list<KeyFrame*> mlNewKeyFrames;
bool LocalMapping::CheckNewKeyFrames()
{
    unique_lock<mutex> lock(mMutexNewKFs);
    return(!mlNewKeyFrames.empty());
}

        我们判断该队列是否为空,即追踪线程传给局部建图线程的关键帧是否为空,若为空,局部建图线程等待关键帧的到来,若不为空,我们进行局部建图线程。

4.3 处理列表中的关键帧,包括计算BoW、更新观测、描述子、共视图,插入到地图等LocalMapping::ProcessNewKeyFrame 

4.3.1 函数最终目的

        ①从mlNewKeyFrames(追踪线程传来的关键帧)拿出一帧mpCurrentKeyFrame进行处理。

        ②计算该关键帧mpCurrentKeyFrame的词袋向量

        ③处理关键帧的地图点:更新地图点平均观测方向、更新该点的平均观测方向和观测距离范围、更新地图点的最佳描述子。

        ④更新关键帧间的连接关系:

        更新下列变量:

        @mConnectedKeyFrameWeights:当前关键帧的共视信息,记录当前关键帧共视关键帧的信息(哪一帧和当前关键帧有共视,共视程度是多少)

        @mvpOrderedConnectedKeyFrames:对mConnectedKeyFrameWeights中超过共视阈值的关键帧(按照共视程度从大到小排序)

        @mvOrderedWeights:对mConnectedKeyFrameWeights中超过共视阈值的关键帧的共视程度(按照共视程度从大到小排序)

        @mpParent:共视程度最高的那个关键帧

        @mspChildrens:建立双向关系,将当前帧的共视程度最高的那个关键帧的子关键帧添加当前帧
        ⑤将该关键帧mpCurrentKeyFrame插入地图

4.3.1 函数解析 

        先从跟踪线程传给局部线程的关键帧队列中取走一帧mlNewKeyFrames.front进行处理(本函数以及之后的函数),这帧放入mpCurrentKeyFrame局部变量中。并将此关键帧移出队列mlNewKeyFrames(我要处理了,并且这帧要处理完)。

        计算该帧的BoW向量(也就是说,只要是关键帧它的BoW向量都会被计算)。

ORB-SLAM2 ---- Frame::ComputeBoW函数https://blog.csdn.net/qq_41694024/article/details/128007040

// 获取当前关键帧的具体的地图点
vector<MapPoint*> KeyFrame::GetMapPointMatches()
{
    unique_lock<mutex> lock(mMutexFeatures);
    return mvpMapPoints;
}

        获得所有的地图点存入vpMapPointMatches向量中。(追踪线程会生成一部分地图点)。遍历每一个地图点。

        如果这个地图点不是来自当前帧的观测(比如来自局部地图点),为当前地图点添加观测。

/**
 * @brief 给地图点添加观测
 *
 * 记录哪些 KeyFrame 的那个特征点能观测到该 地图点
 * 并增加观测的相机数目nObs,单目+1,双目或者rgbd+2
 * 这个函数是建立关键帧共视关系的核心函数,能共同观测到某些地图点的关键帧是共视关键帧
 * @param pKF KeyFrame
 * @param idx MapPoint在KeyFrame中的索引
 */
void MapPoint::AddObservation(KeyFrame* pKF, size_t idx)
{
    unique_lock<mutex> lock(mMutexFeatures);
    // mObservations:观测到该MapPoint的关键帧KF和该MapPoint在KF中的索引
    // 如果已经添加过观测,返回
    if(mObservations.count(pKF)) 
        return;
    // 如果没有添加过观测,记录下能观测到该MapPoint的KF和该MapPoint在KF中的索引
    mObservations[pKF]=idx;

    if(pKF->mvuRight[idx]>=0)
        nObs+=2; // 双目或者rgbd
    else
        nObs++; // 单目
}
// 观测到该MapPoint的KF和该MapPoint在KF中的索引
    std::map<KeyFrame*,size_t> mObservations; 
obs 被观测到的相机数目,单目+1,双目或RGB-D则+2

        因此pMP->AddObservation(mpCurrentKeyFrame, i);这行代码的作用就是更改mObservations变量,使该地图点能被该帧观测并且添加该地图点的观测次数obs。

        由于该地图点的被观察次数可能改变,因此我们需要更新该点的平均观测方向和观测距离范围。

/**
 * @brief 更新地图点的平均观测方向、观测距离范围
 *
 */
void MapPoint::UpdateNormalAndDepth()
{
    // Step 1 获得观测到该地图点的所有关键帧、坐标等信息
    map<KeyFrame*,size_t> observations;
    KeyFrame* pRefKF;
    cv::Mat Pos;
    {
        unique_lock<mutex> lock1(mMutexFeatures);
        unique_lock<mutex> lock2(mMutexPos);
        if(mbBad)
            return;

        observations=mObservations; // 获得观测到该地图点的所有关键帧
        pRefKF=mpRefKF;             // 观测到该点的参考关键帧(第一次创建时的关键帧)
        Pos = mWorldPos.clone();    // 地图点在世界坐标系中的位置
    }

    if(observations.empty())
        return;

    // Step 2 计算该地图点的平均观测方向
    // 能观测到该地图点的所有关键帧,对该点的观测方向归一化为单位向量,然后进行求和得到该地图点的朝向
    // 初始值为0向量,累加为归一化向量,最后除以总数n
    cv::Mat normal = cv::Mat::zeros(3,1,CV_32F);
    int n=0;
    for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
    {
        KeyFrame* pKF = mit->first;
        cv::Mat Owi = pKF->GetCameraCenter();
        // 获得地图点和观测到它关键帧的向量并归一化
        cv::Mat normali = mWorldPos - Owi;
        normal = normal + normali/cv::norm(normali);                       
        n++;
    } 

    cv::Mat PC = Pos - pRefKF->GetCameraCenter();                           // 参考关键帧相机指向地图点的向量(在世界坐标系下的表示)
    const float dist = cv::norm(PC);                                        // 该点到参考关键帧相机的距离
    const int level = pRefKF->mvKeysUn[observations[pRefKF]].octave;        // 观测到该地图点的当前帧的特征点在金字塔的第几层
    const float levelScaleFactor =  pRefKF->mvScaleFactors[level];          // 当前金字塔层对应的尺度因子,scale^n,scale=1.2,n为层数
    const int nLevels = pRefKF->mnScaleLevels;                              // 金字塔总层数,默认为8

    {
        unique_lock<mutex> lock3(mMutexPos);
        // 使用方法见PredictScale函数前的注释
        mfMaxDistance = dist*levelScaleFactor;                              // 观测到该点的距离上限
        mfMinDistance = mfMaxDistance/pRefKF->mvScaleFactors[nLevels-1];    // 观测到该点的距离下限
        mNormalVector = normal/n;                                           // 获得地图点平均的观测方向
    }
}

        这里我之前有说过,不再阐述,主要是修改几个点。

        mfMaxDistance :能看到该地图点的最大距离(用于判定地图点的有效深度的一个变量)

        mfMinDistance :能看到该地图点的最短距离(用于判定地图点的有效深度的一个变量)

        mNormalVector :该地图点的平均观测方向(有很多帧都能观测到该地图点,求一个观测到该地图点的平均角度)

        更新能观测到该点的最佳描述子:

ORB-SLAM2 --- MapPoint::ComputeDistinctiveDescriptors 函数解析https://blog.csdn.net/qq_41694024/article/details/128515977?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22128515977%22%2C%22source%22%3A%22qq_41694024%22%7D        如果这个地图点不是来自当前帧的观测(这些地图点可能来自双目或RGBD跟踪过程中新生成的地图点,或者是CreateNewMapPoints 中通过三角化产生),将上述地图点放入mlpRecentAddedMapPoints,等待后续MapPointCulling函数的检验。

mlpRecentAddedMapPoints.push_back(pMP); 

        更新关键帧间的连接关系(共视图):函数十分重要,在下面链接单独讲述:

ORB-SLAM2 --- KeyFrame::UpdateConnections 函数https://blog.csdn.net/qq_41694024/article/details/128516249        更新下列变量:

        @mConnectedKeyFrameWeights:当前关键帧的共视信息,记录当前关键帧共视关键帧的信息(哪一帧和当前关键帧有共视,共视程度是多少)

        @mvpOrderedConnectedKeyFrames:对mConnectedKeyFrameWeights中超过共视阈值的关键帧(按照共视程度从大到小排序)

        @mvOrderedWeights:对mConnectedKeyFrameWeights中超过共视阈值的关键帧的共视程度(按照共视程度从大到小排序)

        @mpParent:共视程度最高的那个关键帧

        @mspChildrens:建立双向关系,将当前帧的共视程度最高的那个关键帧的子关键帧添加当前帧
        ⑤将该关键帧mpCurrentKeyFrame插入地图

        最后将该关键mpCurrentKeyFrame帧插入地图。

4.4 根据地图点的观测情况剔除质量不好的地图点LocalMapping::MapPointCulling

4.4.1 函数解析

        检查新增地图点,根据地图点的观测情况剔除质量不好的新增的地图点。

        更新mlpRecentAddedMapPoints变量:处理所有新增地图点,确定保留或舍弃。

ORB-SLAM2 --- LocalMapping::MapPointCulling 函数解析https://blog.csdn.net/qq_41694024/article/details/128550672?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22128550672%22%2C%22source%22%3A%22qq_41694024%22%7D

4.5当前关键帧与相邻关键帧通过三角化产生新的地图点,使得跟踪更稳 LocalMapping::CreateNewMapPoints

4.5.1 函数解析

        本函数主要是根据词典向量匹配局部建图线程传来的关键帧与其共视程度最高的几帧进行匹配,利用这些匹配生成地图点,并将地图点存储在mlpRecentAddedMapPoints向量中待检验。

ORB-SLAM2 --- LocalMapping::CreateNewMapPoints解析https://blog.csdn.net/qq_41694024/article/details/128555010

4.6 若已经处理完队列中的最后的一个关键帧,检查并融合当前关键帧与相邻关键帧帧(两级相邻)中重复的地图点LocalMapping::SearchInNeighbors 

4.6.1 函数解析

        本函数进行融合地图点,替换地图点,主要是对关键帧mpCurrentKeyFrame的一级、二级共视关键帧进行操作,并将废弃地图点设置为坏点。

ORB-SLAM2 --- LocalMapping::SearchInNeighbors函数解析icon-default.png?t=MBR7https://blog.csdn.net/qq_41694024/article/details/128560713

4.7 检测并剔除当前帧相邻的关键帧中冗余的关键帧LocalMapping::KeyFrameCulling 

4.7.1 函数解析

        已经处理完队列中的最后的一个关键帧,并且闭环检测没有请求停止LocalMapping的时候如果我们当局部地图中的关键帧大于2个的时候进行局部地图的BA,局部BA后可能存在冗余的关键帧,我们通过此函数检测并剔除当前帧相邻的关键帧中冗余的关键帧。

        简而言之,是一个去除冗余关键帧的操作:

ORB-SLAM2 --- LocalMapping::KeyFrameCulling函数解析icon-default.png?t=MBR7https://blog.csdn.net/qq_41694024/article/details/128567992

4.8 将当前帧加入到闭环检测队列中 

        进行完如上操作后,将该关键帧mpCurrentKeyFrame加入回环检测的关键帧队列mlpLoopKeyFrameQueue中:

// 将某个关键帧加入到回环检测的过程中,由局部建图线程调用
void LoopClosing::InsertKeyFrame(KeyFrame *pKF)
{
    unique_lock<mutex> lock(mMutexLoopQueue);
    // 注意:这里第0个关键帧不能够参与到回环检测的过程中,因为第0关键帧定义了整个地图的世界坐标系
    if(pKF->mnId!=0)
        mlpLoopKeyFrameQueue.push_back(pKF);
}

4.9 当要终止当前线程的时候

        判断:

        ①mbStopped是否为true,为true表示可以并终止localmapping 线程。

        ②检查是否已经有外部线程请求终止当前线程

        我们等待3000ms,然后确定终止了就跳出这个线程的主循环中止该线程。

4.10 等待处理的关键帧列表为空且还没终止当前线程的时候的操作

        查看是否有复位线程的请求:

// 检查是否有复位线程的请求
void LocalMapping::ResetIfRequested()
{
    unique_lock<mutex> lock(mMutexReset);
    // 执行复位操作:清空关键帧缓冲区,清空待cull的地图点缓冲
    
    if(mbResetRequested)
    {
        mlNewKeyFrames.clear();
        mlpRecentAddedMapPoints.clear();
        // 恢复为false表示复位过程完成
        mbResetRequested=false;
    }
}

        清空关键帧缓冲区,清空待cull的地图点缓冲。

        设置允许跟踪线程可以传入局部建图线程关键帧(等待下一轮操作)。

// 设置"允许接受关键帧"的状态标志
void LocalMapping::SetAcceptKeyFrames(bool flag)
{
    unique_lock<mutex> lock(mMutexAccept);
    mbAcceptKeyFrames=flag;
}

        等待3000ms。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/142561.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

十分钟学会在linux上部署chrony服务器(再见 NTP,是时候拥抱下一代时间同步服务 Chrony 了)

chrony服务器 Chrony 相较于 NTPD 服务的优势 安装与配置&#xff08;Chrony的配置文件是/etc/chrony.conf&#xff09; 同步网络时间服务器 设置开机启动&#xff0c;重启服务 chronyc sources 输出结果解析 练习 实验模型图如下 实验a如下 实验b如下 再见 NTP&#x…

中国手机市场全面衰退,连苹果也未能幸免,大跌近三成

CINNO公布了11月份国内手机市场的数据&#xff0c;数据显示2022年11月份中国市场的手机出货量同比下滑21.7%&#xff0c;在整体大环境出现销量下滑的情况下&#xff0c;此前曾持续逆势增长的苹果也顶不住了&#xff0c;苹果在中国市场的出货量也出现了下滑的势头。数据显示2022…

06-Alibaba Nacos注册中心源码剖析

Nacos&Ribbon&Feign核心微服务架构图 架构原理 1、微服务系统在启动时将自己注册到服务注册中心&#xff0c;同时外发布 Http 接口供其它系统调用(一般都是基于SpringMVC) 2、服务消费者基于 Feign 调用服务提供者对外发布的接口&#xff0c;先对调用的本地接口加上注…

JS继承有哪些,你能否手写其中一两种呢?

引言 JS系列暂定 27 篇&#xff0c;从基础&#xff0c;到原型&#xff0c;到异步&#xff0c;到设计模式&#xff0c;到架构模式等&#xff0c; 本篇是 JS系列中第 3 篇&#xff0c;文章主讲 JS 继承&#xff0c;包括原型链继承、构造函数继承、组合继承、寄生组合继承、原型…

前端vue项目发送请求不携带cookie(vue.config.js和nginx反向代理)

一、本地环境——使用vue.config.js配置了跨域代理本来发现问题&#xff0c;是因为后台记录到接收到的sessionId一直在变化&#xff0c;导致需要在同一个sessionId下处理的逻辑无法实现。一开始以为是前后端分离跨域导致的&#xff0c;网上给出了解决方案&#xff1a;main.js中…

线程同步的实现

线程同步 同步就是协同步调&#xff0c;按预定的先后次序进行运行。如:你说完&#xff0c;我再说。 "同"字从字面上容易理解为一起动作 其实不是&#xff0c;"同"字应是指协同、协助、互相配合。 如进程、线程同步&#xff0c;可理解为进程或线程A和B一…

USB子系统简述

引子&#xff1a;关于 lsusb 命令 lsusb 列出系统中所有的USB设备&#xff1a; Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hubBus 004 &#xff1a;表示第四个 usb 主控制器&#xff08;机器上总共有四个 usb 主控制器&#xff0c;可以通过命令 lspci | g…

看完这篇文章终于弄明白了什么是 RocketMQ 的存储模型

RocketMQ 优异的性能表现&#xff0c;必然绕不开其优秀的存储模型 。这篇文章&#xff0c;笔者按照自己的理解 , 尝试分析 RocketMQ 的存储模型&#xff0c;希望对大家有所启发。1 整体概览首先温习下 RocketMQ 架构。整体架构中包含四种角色 :Producer &#xff1a;消息发布的…

基于Python深度学习的垃圾分类代码,用深度残差网络构建

垃圾分类 完整代码下载地址&#xff1a;基于Python深度学习的垃圾分类代码 介绍 这是一个基于深度学习的垃圾分类小工程&#xff0c;用深度残差网络构建 软件架构 使用深度残差网络resnet50作为基石&#xff0c;在后续添加需要的层以适应不同的分类任务模型的训练需要用生…

Qt扫盲-QSerialPort理论总结

QSerialPort理论总结一、概述二、使用流程1. 错误处理2. 阻塞串行端口编程3. 非阻塞串行端口编程三、信号四、注意事项一、概述 QSerialPort 类其实就是一个打开串口&#xff0c;进行串口通信传输数据的功能类。我们可以使用QSerialPortInfo帮助类获取有关可用串行端口的信息&…

JavaEE高阶---Spring AOP

一&#xff1a;什么是Spring AOP&#xff1f; 首先&#xff0c;AOP是一种思想&#xff0c;它是对某一类事情的集中处理。 如用户登录权限的效验&#xff0c;没学 AOP 之前&#xff0c;我们所有需要判断用户登录的页面&#xff0c;都要各自实现或调用验证的方法。然后有了 AOP …

【Linux进程间通信】

Linux进程间通信进程间通信介绍进程间通信的概念进程间通信的目的进程间通信的本质进程间通信的分类管道什么是管道匿名管道匿名管道的原理pipe函数匿名管道使用步骤匿名管道读写规则匿名管道的特点匿名管道的四种特殊情况匿名管道的大小命名管道命名管道的原理使用命令创建命名…

【浮点数在内存中的存储规则】

我们知道&#xff0c;整型在内存中的存储比较简单&#xff0c;在内存中都是以二进制来存储的。然而&#xff0c;浮点型在内存中的存储较为复杂。下面来详细探讨&#xff1a; 直接举一个例子&#xff1a; int main() { int n 9; float *pFloat (float *)&n; printf("…

工业树莓派解决传统数据设备数据上云问题

一、前言 工业4.0的浪潮下&#xff0c;许多中小型制造业企业渴望通过数字化转型谋求新的发展动力&#xff0c;然而&#xff0c;在转型之路上常常会面临一个问题&#xff1a;传统数据采集设备数量多、种类杂&#xff0c;不支持比较新颖的现场总线协议或者通信技术&#xff0c;最…

java 微服务框架介绍 SpringCloud Eureka注册中心 Nacos注册中心

为什么要学习微服务框架 认识微服务 服务架构演变 单体架构 分布式架构 微服务结构 SrpingCloud SpringCloud是目前国内使用最广泛的微服务框架。官网地址&#xff1a;https://spring.io/projects/spring-cloud。 服务拆分及远程调用 服务拆分注意事项 我们查询的时候需要…

Java基础 —— 编程入门

一、比特(bit)和字节(byte)一个0或者一个1存储为一个比特(bit)&#xff0c;是计算机中最小的存储单位。计算机中是最基本的存储单元是字节(byte)。每个字节由8个比特构成。计算机就是一系列的电路开关。每个开关存在两种状态:关(off)和开(on)。如果电路是开的&#xff0c;它的值…

Ubuntu物理真机提高访问速度

这里不适合小白用户&#xff0c;只是做出几点提醒。 iguge学术助手 纯Ubuntu真机&#xff0c;是没办法访问外部网络的&#xff0c;先用百度搜索iguge下载一个&#xff0c;安装在Firefox浏览器插件上&#xff08;edge或者chrome也行&#xff09;。 免费的不好用&#xff0c;建…

算法之初始动态规划

目录 前言&#xff1a; 初始动态规划 0-1背包问题 0-1背包问题升级版 问题&#xff1a;如何巧妙解决“双十一”购物是的凑单问题&#xff1f; 总结&#xff1a; 前言&#xff1a; 淘宝的“双十一”购物节有各种促销活动&#xff0c;比如“满 200 元减 50 元”。假设你女朋友…

SpringBoot使用 axis 实现webservice客户端(亲测可行)

目录一、webservice在线验证服务端接口地址二、使用 axis 实现webservice客户端代码示例2.1、服务端地址使用qq在线接口验证接口2.2、webservice客户端示例代码一、webservice在线验证服务端接口地址 qq 在线验证接口&#xff1a;http://www.webxml.com.cn/webservices/qqOnli…

[飞腾]Trace32使用概述

最近将多年来收集到的教学视频、国内外图书、源码等整理整合拿出来&#xff0c;涉及arm、Linux、python、信号完整性、FPFA、DSP、算法、stm32、单片机、制图、电子模块、kali、出版社图书等。资料目前约1.5TB。资料详情请参阅&#xff1a; 1.5TB电子工程师资料详细介绍https:/…