2022年MathorCup数学建模B题无人仓的搬运机器人调度问题解题全过程文档加程序

news2024/9/23 23:27:12

2022年第十二届MathorCup高校数学建模

B题 无人仓的搬运机器人调度问题

原题再现

  本题考虑在无人仓内的仓库管理问题之一,搬运机器人 AGV 的调度问题。更多的背景介绍请参看附件-背景介绍。对于无人仓来说,仓库的地图模型可以简化为图的数据结构。
仓库地图:
  无人仓内的设施,可以细分为 AGV 能行驶的道路节点,和别的功能节点(如工位,储位等)。这样,仓库地图模型可以抽象为这些节点构成的图,再按 AGV 能到达的节点来添加图的边。简单来说,附件仓库地图数据(map.csv)通过描述节点类型,以及节点之间的关系(边),可以构建如下图 1 所示的仓库地图。
在这里插入图片描述
  仓库地图数据(map.csv)是按 csv 格式存储,其节点类型有如下几类,在上图中用不同颜色标注。
  1) 路径节点(灰色):AGV 可以自由通行。
  2) 储位节点(绿色):放置托盘或者普通货架,AGV 可以到达。一般只有一个位置可以进出,即靠近道路的位置。
  3) 保留节点(黄色):保留位置。
  4) 柱子节点(黑色):障碍物,AGV 不能到达。
  5) 拣选工位节点(蓝色):拣选机器人在这里把商品打包后从传送带出库,一般有多个托盘停靠位。
  6) 补货位节点(粉色):从高密度区补货的商品放置点,一般通过传送带输送。
  7) 空托盘回收节点(红色):空托盘回收处,图中只有两处。
无人仓任务场景:
  假设仓库地图按上述方式抽象成图,搬运机器人 AGV—次只搬运一个托盘(带有多种商品),能执行从一个地图节点na移动到nb的路径指令,其中每一步只能移动到有边相连的地图节点,不能斜着移动。附件中机器人数据(agv.csv)里,给出了 20 个搬运机器人 AGV 在仓库地图上的初始位置坐标。
  假设仓库内商品都是中大件商品,每个在储位的托盘上叠放着多种商品,附件中的库存数据(pallets.csv)给岀了全部托盘的位置以及托盘上放的商品信息。对于中件仓来说,即使用户订单包含了多个商品,实际发货还是一个商品一个包裹。这样,AGV 执行任务只需要尽快满足商品数目的要求,不需要等待同一订单中的全部商品到齐后才能出库。所以附件订单数据(orders.csv)里,每个订单只有同一件商品以及对应的数量。
  无人仓流程是根据给定的一段时间内订单数据流,结合当前库存情况,统筹安排搬运机器人从储位搬运有需求商品的托盘到附近的拣选工位(即出库任务),拣选完成后需安排搬运工位处的非空托盘到空储位(即回库任务),或者安排搬运工位处的空托盘到托盘回收处(即回收任务)等。本题只考虑这三种主要任务场景,即出库、回库、回收任务。
  首先,对于出库任务,搬运机器人 AGV 把一个托盘搬运到拣选工位。但是对于同一个工位来说,同时能容纳放置的托盘数目是有限的。假设每个拣选工位有 b 个停靠位,也就是能同时最多分派 b 个出库任务到同一个拣选工位,直到执行回库或者回收任务,有空停靠位后才能容纳新的出库托盘。
  其次,出库任务完成后,搬运机器人处于空闲状态,可以被安排执行下一个任务,而不需要在停靠位等候着。不妨假设出库托盘在拣选工位需要停留一段时间后,等拣选机器人打包发货后才能进行后续的回库或者回收任务。这里假设停留时间固定为t0,也就是说,无论需要拣选多少商品,都简化为停留时间t0后,该托盘可以被执行后续的回库和回收任务。
无人仓总结:
  无人仓的主要运行场景就是安排搬运机器人 AGV 执行如下各种任务。
  •出库:AGV 搬运载有商品的托盘到空闲拣选工位
  •回库:AGV 搬运拣选完成的托盘从工位回到仓库内空储位
  •回收:AGV 搬运拣选完成的空托盘从工位到托盘回收处
  无人仓的核心是统筹优化上述任务的执行来最大化出库效率,安排AGV 任务和路线需满足全局最优,达到实时响应,并避免拥堵/死锁等情况发生。也需要均衡拣选工位之间的工作量。

问题 1:AGV 统筹调度的最佳策略

  假设先不考虑搬运机器人在执行任务时可能的碰撞问题,请在无人仓模型下设计调度算法,根据附件中订单数据(orders.csv),和仓库内的库存数据(pallets.csv),对于给定的 20 个搬运机器人(agv.csv),统筹调度和安排 AGV 任务,直到满足所有的订单需求,即全部拣选工位都空闲为止。这里,目标函数为在每个搬运机器人尽可能忙的同时,最小化全部搬运机器人的行走总路径。
  下面左图中,用红色圆圈表示 AGV,用绿色方块表示货架或者托盘,用蓝色 X 表示拣选工位。右图中匹配了最近的 AGV、托盘和工位,使得指定AGV 去取托盘后再送到工位拣选。

在这里插入图片描述
  注意,现实场景中的目标其实是全局优化出库效率,节省人力,避免高峰期出现"爆仓”现象。所以更合适的衡量指标是时间上的,要求在最短的时间内满足订单需求。在某种程度上,目标可以转化为使得每个拣选工位尽可能忙,即最小化最忙拣选工位的工作时长。另一方面,仓库内搬运机器人 AGV 的合理投放数量一般是拣选工位的常数倍,因为投放太多的话出库效率不但不会改善,反而增加 AGV 拥堵的可能性。进一步考虑到每个工位可以增加停靠位,而且搬运机器人除了出库任务,还有回库和回收等任务。所以使得每个 AGV 尽可能忙,然后最小化全部 AGV 行走总路径,也是合理的模型目标简化。

问题 2:任务均衡区域划分

  为了更好地平衡拣选工位的负载,同时预防搬运机器人的局部拥堵,根据拣选工位和库存商品数量对仓库地图进行动态分区。也就是对仓库内储位上的每个托盘,都指定一个默认拣选工位。
  请建立优化模型,使得每个拣选工位对应托盘的商品总量尽可能地平均,同时要求最小化全部托盘到其默认拣选工位距离总和。类似下图 3 所示的区域划分。
  进一步,根据某段时间内所需出库商品的库存分布,再结合问题一的AGV 调度算法,更合理地均衡每个拣选工位在某段时间内的工作量。

在这里插入图片描述

问题 3:避免碰撞和拥堵

  在问题一和问题二的基础上,进一步考虑搬运机器人的碰撞和拥堵问题。当仓库内同时有多个 AGV 在执行任务时,不可避免有些 AGV 在某个路径节点上相遇。特别地,如果两个 AGV 在一条货架窄巷道上相遇,那么需要其中一个 AGV 避让。
  在合理的假设下,请设计算法和防碰撞策略,使得搬运机器人能智能地避免碰撞。特别是在一些特殊节点处(如托盘回收处),避免出现多个AGV 的拥堵,和可能的死锁场景。
  下图是一个死锁场景示例,一个 AGV 去拣选工位取空托盘,另一台AGV 去相邻停靠位放置托盘,他们占据了各自的前进路径节点后都不退让,造成了死锁。

在这里插入图片描述

整体求解过程概述(摘要)

  针对无人仓的多搬运机器人的路径规划问题,本文综合运用了多目标规划、遗传算法和交通管制法等方法,充分发挥了线性加权和 banach 空间中的向量范数等思想的优势,根据题意构建具体的线性规划模型,并借助 python 软件编程求解。
  首先我们对给出的数据进行数据预处理:1)根据 map.csv 中的仓库地图数据,基于每一个节点的坐标画出无向图,基于节点关系构建出邻接矩阵;2)根据邻接矩阵,运用 Floyd 算法求解每个点到其他点的最短距离,得到距离矩阵和路由矩阵;3)通过Python 软件以栅格的形式进行可视化呈现。通过可视化的栅格仓库图,删除不符合实际的数据,因此,在该无人仓中实际可用的小车数量为 19 辆。
  针对问题一,本题要求满足以下约束:1)满足所有的订单需求,即实现全部拣选工位都空闲;2)保证在搬运过程中每个机器人尽可能忙;3)每个拣选工位同时容纳的托盘数不超过 3 个停靠位,最终实现最小化全部搬运机器人的行走路径的目标函数。因此,根据题意,我们构建单目标规划模型,基于托盘搬运顺序进行编码,并采用改进的遗传算法和模拟退火两种方法进行对比求解。通过改进的遗传算法求解后可以得到,所有 AGV 的路径总长度为 7316;通过模拟退火算法求解后可以得到所有 AGV 的路径总长度为 7428。通过两种方式的比较,可以得到改进遗传算法使得 AGV 以更短的路径搬运完所需要的商品。
  针对问题二,本题需要满足以下约束:1)每个拣选工位对应托盘的商品总量尽可能地平均;2)最小化全部托盘到其默认拣选工位距离总和;3)对仓库内储位上的每个托盘,都指定一个由第一阶段的目标规划唯一确定的默认拣选工位,最终实现全部搬运机器人的行为总路径最小的目标函数。本题在问题一的基础上,需要对仓库进行合理分区。因此,本题建立了两阶段的目标规划模型,其中约束条件 1)和 2)属于第一阶段动态分区规划模型,目的是为了实现仓库的合理分区,约束条件 3)则是在第一阶段的基础上新增加的约束条件,属于第二阶段的路径规划模型。本题设计一种具有新型编码方式的遗传算法来实现储位的分区,通过求解后可以得到在分区情况下所有 AGV 的移动总路径长度为 7453。
  针对问题三,本题在满足问题一和问题二的基础上,需要进一步考虑搬运机器人的碰撞和拥堵问题。首先本文确定了路径冲突的三种类型:垂直冲突、相向冲突和追尾冲突,以及通过向量内积进行路径冲突类型的判断。其次,我们建立了交通管制法和优先级规划法模型,并在 AGV 为 12-19 辆的不同情况下均进行 100 次随机实验,最终得到最优的 AGV 数量规划,防止多 AGV 在仓库内的碰撞和拥堵问题。通过模型的求解可以得到在交通管制法下所有 AGV 的总路径最短,且当 AGV 数量减少为 15 时,减少碰撞和拥堵情况是最佳的。

模型假设:

  1. 搬运机器人 AGV 完成出库任务后不在停靠位等候,立刻进行回库或者回收任务(且下一个托盘到达拣选工位节点时,前一个托盘必定已完成拣选工作),若拣选工位无托盘,则直接进行下一次出库任务。
  2. 满足所有的订单需求时,托盘可置于拣选工位,搬运机器人 AGV 不需要进行回库或者回收任务。
  3. 保留节点,视为柱子节点,即障碍物,搬运机器人 AGV 不能到达。
  4. 若订单中的货物量超过储位的总量,由补货位节点从高密度区补货的商品放置点通过传送带进行输送,此时不增加搬运机器人 AGV 的工作负担。
  5. 出库托盘在拣选工位需要停留一段时间后,等拣选机器人打包发货后才能进行后续的回库或者回收任务。
  6. 搬运机器人 AGV 在工作时进行匀速运动,且各相邻栅格间的距离相等,搬运机器人 AGV 通过一个栅格均需要一个单位时间。
  7. 假设搬运机器人 AGV 不再进行新任务,但全部拣选工位未都空闲为止时,将搬运机器人 AGV 从拣选工位节点人工移出。

问题分析:

问题一的解析

  问题一在不考虑 AGV 机器人存在可能碰撞的问题,设计多 AGV 的调度算法,需要满足以下目标:(1)满足所有订单;(2)让每个机器人尽量忙;(3)全部搬运机器人的行走总路径最小;(4)最忙拣选工位的工作时长最短;(5)在最短的时间内满足订单需求。通过本题的求解,我们可以得到一个合理的多 AGC 的路径规划。具体如图 1-2,红色圆圈表示 AGV,绿色方块表示货架或者托盘,蓝色 X 表示拣选工位,左图为初始各点的分布状态,右图为匹配了最近的 AGV、托盘和工位,使得指定 AGV 去取托盘后再送到工位拣选。
在这里插入图片描述

问题二的解析

  为了更好地平衡拣选工位的负载,同时预防搬运机器人的局部拥堵,根据拣选工位和库存商品数量对仓库地图进行动态分区。也就是对仓库内储位上的每个托盘,都指定一个默认拣选工位。本题要在问题一的基础上,对 AGV 调度算法进行优化,使得每个拣选工位对应托盘的商品总量尽可能平均,同时要求最小化全部托盘到其默认拣选工位距离总和,更加合理地均衡每个拣选工位在某段时间内的工作量。如图 1-3,对储位区域进行分区,为其分配相对应的默认拣选工位。
在这里插入图片描述

问题三的解析

  本题考虑了 AGV 的碰撞和拥堵问题,当仓库内同时有多个 AGV 在执行任务时,不可避免有些 AGV 在某个路径节点上相遇,甚至在一些特殊节点处(如托盘回收处),可能还会出现多个 AGV 的拥堵甚至死锁场景。在这样的情况旨在,势必需要有 AGV进行避让,因此本题在问题一和问题二的基础上,考虑可能出现的碰撞情形,在合理的假设下,优化算法,使其具有一定的防碰撞能力。

模型的建立与求解整体论文缩略图

在这里插入图片描述
在这里插入图片描述

全部论文请见下方“ 只会建模 QQ名片” 点击QQ名片即可

程序代码:(代码和文档not free)

The actual procedure is shown in the screenshot

#include<bits/stdc++.h>
#define MAXN 60 //最大工作量
#define INIT_PRE 3000//道路初始信息素量
#define K 2000 //循环次数
#define DIS 0.5 //信息素消散速率
#define SUPER_START 48
using namespace std;
int totalStep;
int Step[MAXN];
int phe[MAXN][MAXN][MAXN][MAXN];
int n,m;
struct Pair
{
    int i,j;
    void get(int a,int b)
    {
        i=a;j=b;
    }
}Jobnum[MAXN];
struct Job
{
    int machine;
    int len;
}job[MAXN][MAXN];
struct Ant
{
    int JobStep[MAXN]; //任务已运行步数
    int path[MAXN];
    int pathlen;
    int getFullPath()
    {
        int sum=0;
        for (int i=0;i<pathlen;i++)
            sum+=path[i];
        return sum;
    }
    Pair paths[MAXN];
};
void init()
{
    //totalStep=0;
    memset(phe,0,sizeof(phe));
    for (int i=0;i<totalStep;i++)
    for (int j=0;j<totalStep;j++)
    for (int k=0;k<totalStep;k++)
    for (int l=0;l<totalStep;l++)
        phe[i][j][k][l]=INIT_PRE;
    for (int i=0;i<totalStep;i++)
    for (int j=0;j<totalStep;j++)
        phe[SUPER_START][SUPER_START][i][j]=INIT_PRE;
    return;
}
void Dissipation()
{
    for (int i=0;i<totalStep;i++)
    for (int j=0;j<totalStep;j++)
    for (int k=0;k<totalStep;k++)
    for (int l=0;l<totalStep;l++)
        phe[i][j][k][l] *= DIS;
    for (int i=0;i<totalStep;i++)
    for (int j=0;j<totalStep;j++)
        phe[SUPER_START][SUPER_START][i][j]*= DIS;
    return;
}
struct Recording
{
    int start;
    int ed;
    int job;
    int machine;
};
int timeCalcu(int Job[], bool draw)
{
    int sum=0;
    int machineWorkTime[MAXN];
    int JobLast[MAXN];
    int JobStep[MAXN];
    Recording rec[MAXN];
    memset(machineWorkTime,0,sizeof(machineWorkTime));
    memset(JobLast,0,sizeof(JobLast));
    memset(JobStep,0,sizeof(JobStep));
    memset(rec,0,sizeof(rec));
    for (int k = 0; k < totalStep; k++)
    {
        int i = Job[k];
        rec[k].start = max(JobLast[i],machineWorkTime[job[i][JobStep[i]].machine]);
        rec[k].job = i;
        rec[k].ed = rec[k].start + job[i][JobStep[i]].len;
        JobLast[i] = rec[k].ed;
        rec[k].machine = job[i][JobStep[i]].machine;
        machineWorkTime[job[i][JobStep[i]].machine] = rec[k].ed;
        JobStep[i]++;
    }
    for (int i = 0; i < m; i++)
    {
        sum = max(sum,machineWorkTime[i]);
    }
    if (draw == true)
    {
        int gantt[MAXN][MAXN];
        memset(gantt,0,sizeof(gantt));
        for (int i=0;i<totalStep;i++)
        {
            for (int j=rec[i].start;j<rec[i].ed;j++)
            {
                gantt[rec[i].machine][j]=rec[i].job+1;
            }
        }

        for (int i=0;i<m;i++)
            for (int j=0;j<sum;j++)
                printf("%d%c",gantt[i][j],j==sum-1?'\n':' ');
    }
    return sum;
}
int main()
{
    while (~scanf("%d%d",&n,&m))
    {
        totalStep = 0;
        for (int i=0;i<n;i++)
        {

            scanf("%d",&Step[i]);
            totalStep+=Step[i];
            for (int j=0;j<Step[i];j++)
            {
                scanf("%d%d",&job[i][j].machine,&job[i][j].len);
            }
        }
        init();
        int antnum=totalStep*2;
        Ant ant[antnum+5];
        Ant bestAnt;
        int bstime = 999999;
        for (int sl=0;sl<10;sl++)
        {
            //printf("%d/10\n",sl);
            srand(time(0));
            memset(ant,0,sizeof(ant));
            for (int i=0;i<antnum;i++)//第i只蚂蚁的旅程
            {
                //printf("sl=%d/%d\n",i,antnum);
                    int nowJob=SUPER_START; //作为图的超级源点
                    ant[i].JobStep[nowJob]=SUPER_START;
                for (int j=0;j<totalStep;j++)
                {
                    int allpre=0;

                    for (int k=0;k<m;k++)
                    {
                        //printf("i:%d j:%d k:%d l:%d ant:%d\n",nowJob,ant[i].JobStep[nowJob],k,ant[i].JobStep[k],i);
                        if (ant[i].JobStep[k]==Step[k]) continue;
                        allpre += phe[nowJob][ ant[i].JobStep[nowJob] ][k][ ant[i].JobStep[k] ];
                    }
                    //printf("%d\n",allpre);
                    int randSelectNum = rand()*rand() % allpre;//printf("OK\n");
                    //printf("摇到的数字是:%d\n",randSelectNum);
                    int select=0;
                    while (randSelectNum>=0)
                    {
                        if (ant[i].JobStep[select]==Step[select]) {select++;continue;}
                        randSelectNum -= phe[nowJob][ ant[i].JobStep[nowJob] ][select][ ant[i].JobStep[select] ];
                        select++;
                    }
                    select--;
                    //printf("蚂蚁选择了%d\n",select);
                     //蚂蚁选中的任务
                    ant[i].path[ant[i].pathlen]=select;
                    ant[i].paths[ant[i].pathlen++].get(select,ant[i].JobStep[select]);
                    ant[i].JobStep[select]++;
                    nowJob = select;
                    //printf("选择任务%d 阶段%d\n",select,ant[i].JobStep[select]);
                }
            }

            Dissipation(); //每次蚂蚁行走完后,信息素都会消散

            for (int i = 0; i < antnum; i++)
            {
                int ans = timeCalcu(ant[i].path,false);
                if (ans<bstime && totalStep<=ans)
                {
                    bstime = ans;
                    bestAnt = ant[i];
                }
                int reward = 2000/ans; //答案越小,奖励越多。
                for (int j=0;j<ant[i].pathlen-1;j++)
                {
                    int a = ant[i].paths[j].i;
                    int b = ant[i].paths[j].j;
                    int c = ant[i].paths[j+1].i;
                    int d = ant[i].paths[j+1].j;

                    phe[a][b][c][d] += reward;
                }
            }

            //if (sl==1999)
            /*for (int i = 0; i < antnum; i++)
            {
                for (int j=0; j<ant[i].pathlen; j++)
                {
                    printf("%d%c",ant[i].path[j]+1,j==ant[i].pathlen-1?'\n':' ');
                }
                printf("\n%d\n",timeCalcu(ant[i].path,true));
            }*/
        }
        printf("bestTime:%d\n",bstime);
        printf("甘特图:\n");
        timeCalcu(bestAnt.path,true);
        printf("加工顺序为:");
        for (int i=0;i<totalStep;i++)
            printf("%d%s",bestAnt.path[i]+1,i==totalStep-1?"\n":"->");
        /*int a[10] = {1,2,1,0,2,1,0,0};
        timeCalcu(a,true);*/
        return 0;
    }
}

全部论文请见下方“ 只会建模 QQ名片” 点击QQ名片即可

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

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

相关文章

面试常问【进程间通信】最详细解说

文章目录 目录 文章目录 一、进程间有哪几种的通信方式 1.为什么需要进程间通信? 2.进程通信的几种方式 3.进程间通信的目的 二、管道 1.匿名管道 2.命名管道 3.管道总结 三、消息队列 四、共享内存 1.共享内存的原理 2.共享内存的接口 1.创建共享内存 2.将共享内存附加到进程…

HBase---Hbase安装(单机版)

Hbase安装单机版 文章目录Hbase安装单机版Master/Slave架构安装步骤配置Hbase1.上传压缩包解压更名修改hbase-env.sh修改hbase-site.xml配置HBase环境变量配置Zookeeper复制配置文件修改zoo.cfg配置文件修改myid配置Zookeeper环境变量刷信息配置文件启动hbase步骤hbase shellMa…

BS系统中的安全方案(SSO和Oauth2认证,数据加密)

摘要用户用浏览器打开网站&#xff0c;DNS会根据域名找到相应的服务器IP给到浏览器&#xff0c;仅接着用户的浏览器会与服务器建立连接&#xff0c;通过网路上的各个设备(交换机、路由器、基站、光纤等)&#xff0c;将服务器上的数据发送到用户的电脑上&#xff0c;在浏览器里呈…

运输层概述及web请求

运输层 运输层概述 运输层向高层用户屏蔽了下面网络核心的细节&#xff08;如网络拓扑、所采用的路由选择协议等&#xff09;它使应用进程看见的就好像是在两个运输层实体之间有一条端到端的逻辑通信信道&#xff1b; 根据需求不同&#xff0c;运输层提供两种运输协议 面向连…

buffer它到底做了个啥,源码级分析linux内核的文件系统的缓冲区

最近一直在学习linux内核源码&#xff0c;总结一下 https://github.com/xiaozhang8tuo/linux-kernel-0.11 自己整理过的带注释的源码。 为什么要有buffer ​ 高速缓冲区是文件系统访问块设备中数据的必经要道(PS:如果所有程序结果都不落盘&#xff0c;只是int a, a直接在主存…

TryHackMe-Debug(ez php反序列化)

Debug Linux机器CTF&#xff01;您将了解枚举&#xff0c;查找隐藏的密码文件以及如何利用php反序列化&#xff01; 端口扫描 循例&#xff0c;nmap Web枚举 进到web是apache默认页面&#xff0c;直接开扫 由于题目告诉我们涉及php反序列化&#xff0c;那直接找php文件来看&…

Linux学习第十四节-shell脚本

1.Shell概述 Shell连接了用户和Linux内核&#xff0c;他可以解释用户输入的命令传输给内核&#xff0c;让用户可以更加方便的使用Linux系统&#xff1b; Shell本身并不是内核的一部分&#xff0c;他只是站在内核的基础上编写一个应用程序&#xff1b; Shell具备编程的能力&a…

C++回顾(八)—— 继承

8.1 继承的概念 继承是类与类之间的关系&#xff0c;是一个很简单很直观的概念&#xff0c;与现实世界中的继承类似&#xff0c;例如儿子继承父亲的财产。 继承&#xff08;Inheritance&#xff09;可以理解为一个类从另一个类获取成员变量和成员函数的过程。例如类 B 继承于类…

jconsole远程linux下的tomcat

修改Tomcat的配置 进去 Tomcat 安装目录下的 bin 目录&#xff0c;编辑 catalina.sh vi catalina.sh定位到 ----- Execute The Requested Command ----------------------------------------- vi 编辑模式下&#xff0c;点击 Esc&#xff0c;输入 / &#xff0c;然后粘贴 -…

什么是Netty

一&#xff0e;Netty介绍 1.什么是netty Netty 是由 JBOSS 提供的一个 Java 开源框架。Netty 提供异步的、基于事件驱动的网络应用程序框架&#xff0c;用以快速开发高性能、高可靠性的网络 IO 程序,是目前最流行的 NIO 框架&#xff0c;Netty 在互联网领域、大数据分布式计算…

自动驾驶介绍系列 ———— 看门狗

文章目录硬件看门狗软件看门狗差异分析延申窗口看门狗硬件看门狗 硬件看门狗的本质上是一个定时器电路。通常存在一个输入&#xff0c;输入到MCU的RST端。在正常工作状态下&#xff0c;MCU每隔固定时间间隔会输出一个信号给RST端&#xff0c;实现对看门狗端清零。如果在指定的时…

RK3568驱动OV13850摄像头模组调试过程

摄像头介绍品牌&#xff1a;Omnivision型号&#xff1a;CMK-OV13850接口&#xff1a;MIPI像素&#xff1a;1320WOV13850彩色图像传感器是一款低电压、高性能1/3.06英寸1320万像素CMOS图像传感器&#xff0c;使用OmniBSI?技术提供了单-1320万像素&#xff08;42243136)摄像头的…

C++20 协程体验

1 介绍协程是比线程更加轻量级并发编程方式&#xff0c;CPU资源在用户态进行切换,CPU切换信息在用户态保存。协程完成异步的调用流程&#xff0c;并对用户展示出同步的使用方式。协程的调度由应用层决定&#xff0c;所以不同的实现会有不同的调度方式&#xff0c;调度策略比较灵…

麻雀算法SSA优化LSTM长短期记忆网络实现分类算法

1、摘要 本文主要讲解&#xff1a;麻雀算法SSA优化LSTM长短期记忆网络实现分类算法 主要思路&#xff1a; 准备一份分类数据&#xff0c;数据介绍在第二章准备好麻雀算法SSA&#xff0c;要用随机数据跑起来用lstm把分类数据跑起来将lstm的超参数交给SSA去优化优化完的最优参数…

Python可变对象与不可变对象的浅拷贝与深拷贝

前言 本文主要介绍了python中容易面临的考试点和犯错点&#xff0c;即浅拷贝与深拷贝 首先&#xff0c;针对Python中的可变对象来说&#xff0c;例如列表&#xff0c;我们可以通过以下方式进行浅拷贝和深拷贝操作&#xff1a; import copya [1, 2, 3, 4, [a, b]]b a …

小众实用!5款不为人知的Windows软件,让你工作更轻松

分享5款冷门但值得下载的Windows软件&#xff0c;个个都是实用&#xff0c;你可能一个都没见过&#xff0c;但是 我觉得你用过之后可能就再也离不开了。 1.键盘可视化——Keyviz Keyviz是一款免费开源的小工具&#xff0c;它的作用是可以实时展示键盘的操作&#xff0c;就可以…

编程语言分类

目录 ❤ 机器语言 机器语言的编程 ❤ 汇编语言 ❤ 高级语言(编程语言) 编译型 解释型 ❤ 动态语言和静态语言 ❤ 强类型定义语言和弱类型定义语言 ❤ 主流语言介绍 C语言 C java python JavaScript SQL PHP python从小白到总裁完整教程目录:https://blog…

浅入浅出keepalived+mysql实现高可用双机热备

当数据库发生宕机的情况&#xff0c;如果配置了数据库主从同步模式或主主同步模式&#xff0c;则可以从从库中获取数据。 当数据库发生宕机的情况&#xff0c;要求应用系统实现高可用&#xff0c;应用系统不会受到影响&#xff0c;需要对mysql进行双机热备实现数据库的高可用。…

断点调试(debug)

目录 F8案例 ​编辑 debug过程中报错 ​编辑用debug查看方法源码 一层一层查看 Arrays.sort()方法 F9 DebugExercise 介绍&#xff1a;断点调试是指在程序的某一行设置一个断电&#xff0c;调试时&#xff0c;程序运行到这一行就会停住&#xff0c;然后可以一步步往下调试…

微服务引擎 MSE 企业版全新升级

作者&#xff1a;流士 随着企业应用大规模云上迁徙与应用微服务化步伐加快&#xff0c;微服务治理的重要性对企业不言而喻&#xff0c;但微服务治理本身的规范化与标准化尚未形成&#xff0c;导致很多企业在微服务治理方面正经历着痛苦的试错期&#xff0c;甚至难以满足线上环境…