自动驾驶算法(一):Dijkstra算法讲解与代码实现
目录
0 本节关键词:栅格地图、算法、路径规划
1 Dijkstra算法详解
2 Dijkstra代码详解
0 本节关键词:栅格地图、算法、路径规划
1 Dijkstra算法详解
用于图中寻找最短路径。节点是地点,边是权重。
从起点开始逐步扩展,每一步为一个节点找到最短路径:
While True:
1.从未访问的节点选择距离最小的节点收录(贪心思想)
2.收录节点后遍历该节点的邻接节点,更新距离我们举例子说明一下,在机器人路径规划中,通常用open list、closed list表达:
open list 表示从该节点到起点已经有路径的节点
closed list 表示已经找到最短路径的节点
Step1:从起点开始,将起点放入open list中,选择距离最短的节点进行收录。
open list 1(0)(min) closed list| |open list closed list 1(0)Step2:遍历1号节点的邻接节点(4、2号节点)
open list 2(2)(1-->2) 4(1)(1-->4)(min) closed list 1(0)| |open list 2(2)(1-->2) closed list 1(0) 4(1)(1-->4)4号节点收录后我们需要对其邻接节点更新距离。(3、6、7号节点)
Step3:3号节点我们找到1->4->3路径,6号节点我们找到1->4->6路径,7号节点我们找到1->4->7路径。
open list 2(2)(1-->2)(min) 3(3)(1-->4-->3) 6(9)(1-->4-->6) 7(5)(1-->4-->7) closed list 1(0)| |open list 3(3)(1-->4-->3) 6(9)(1-->4-->6) 7(5)(1-->4-->7) closed list 1(0) 4(1)(1-->4) 2(2)(1-->2)Step4:遍历2的邻接节点,我们发现4号节点已经在close list中(不需要被更新),我们更新5号节点。
open list 3(3)(1-->4-->3)(min) 6(9)(1-->4-->6) 7(5)(1-->4-->7) 5(13)(1->2-->5) closed list 1(0)| |open list 6(9)(1-->4-->6) 7(5)(1-->4-->7) 5(13)(1->2-->5) closed list 1(0) 4(1)(1-->4) 2(2)(1-->2) 3(3)(1-->4-->3)Step5:遍历3的邻接节点,(3-->1无需更新,更新3-->6 1436(8) (因为我们有到3的最短距离)),而我们已经为6号节点找到路径6(9)(146),更新6号节点的路径。
open list 6(9)(1-->4-->6)(1->4->3-->6 7) 7(5)(1-->4-->7)(min) 5(13)(1->2-->5) closed list 1(0) 4(1)(1-->4) 2(2)(1-->2) 3(3)(1-->4-->3)| |open list 6(8)(1->4->3-->6) 5(13)(1->2-->5) closed list 1(0) 4(1)(1-->4) 2(2)(1-->2) 3(3)(1-->4-->3) 7(5)(1-->4-->7)Step6:遍历7的邻接节点(6号节点)(1 4 7 6 = 6)比之前的8小,对6号距离再次更新。
open list 6(8)(1->4->3-->6)(1->4->7-->6 6)(min) 5(13)(1->2-->5) closed list 1(0) 4(1)(1-->4) 2(2)(1-->2) 3(3)(1-->4-->3) 7(5)(1-->4-->7) | |open list 5(13)(1->2-->5) closed list 1(0) 4(1)(1-->4) 2(2)(1-->2) 3(3)(1-->4-->3) 7(5)(1-->4-->7) 6(6)(1-->4-->7-->6)Step7:遍历6的邻接节点(6号节点)结束
栅格地图初介绍:
假设图中灰色的是障碍物,红色的是机器人。在避障时,我们的常用做法是通过膨胀障碍物,将机器人视为质点来规划路径,然后对地图进行栅格化,将地图弄成一块一块的。最后将栅格地图转化为有权地图。我们可以把栅格地图的每个栅格看作是有权图的节点,机器人的运动范围可以看作是有权图的节点和节点之间的连接。
2 Dijkstra代码详解
这里我们先配置下代码环境,最好是在python3.9下,我们创建conda虚拟环境:
conda create -n nav python=3.9安装所需库:
pip install numpy scipy matplotlib pandas cvxpy pytest -i https://pypi.tuna.tsinghua.edu.cn/simple我们的代码如下:
"""Grid based Dijkstra planningauthor: Atsushi Sakai(@Atsushi_twi)"""import matplotlib.pyplot as plt import mathshow_animation = Trueclass Dijkstra:def __init__(self, ox, oy, resolution, robot_radius):"""Initialize map for planningox: x position list of Obstacles [m]oy: y position list of Obstacles [m]resolution: grid resolution [m]rr: robot radius[m]"""self.min_x = Noneself.min_y = Noneself.max_x = Noneself.max_y = Noneself.x_width = Noneself.y_width = Noneself.obstacle_map = Noneself.resolution = resolutionself.robot_radius = robot_radiusself.calc_obstacle_map(ox, oy)self.motion = self.get_motion_model()class Node:def __init__(self, x, y, cost, parent_index):self.x = x # index of gridself.y = y # index of gridself.cost = cost # g(n)self.parent_index = parent_index # index of previous Nodedef __str__(self):return str(self.x) + "," + str(self.y) + "," + str(self.cost) + "," + str(self.parent_index)def planning(self, sx, sy, gx, gy):"""dijkstra path searchinput:s_x: start x position [m]s_y: start y position [m]gx: goal x position [m]gx: goal x position [m]output:rx: x position list of the final pathry: y position list of the final path"""start_node = self.Node(self.calc_xy_index(sx, self.min_x),self.calc_xy_index(sy, self.min_y), 0.0, -1) # round((position - minp) / self.resolution)goal_node = self.Node(self.calc_xy_index(gx, self.min_x),self.calc_xy_index(gy, self.min_y), 0.0, -1)open_set, closed_set = dict(), dict() # key - value: hash表open_set[self.calc_index(start_node)] = start_nodewhile 1:c_id = min(open_set, key=lambda o: open_set[o].cost) # 取cost最小的节点current = open_set[c_id]# show graphif show_animation: # pragma: no coverplt.plot(self.calc_position(current.x, self.min_x),self.calc_position(current.y, self.min_y), "xc")# for stopping simulation with the esc key.plt.gcf().canvas.mpl_connect('key_release_event',lambda event: [exit(0) if event.key == 'escape' else None])if len(closed_set.keys()) % 10 == 0:plt.pause(0.001)# 判断是否是终点if current.x == goal_node.x and current.y == goal_node.y:print("Find goal")goal_node.parent_index = current.parent_indexgoal_node.cost = current.costbreak# Remove the item from the open setdel open_set[c_id]# Add it to the closed setclosed_set[c_id] = current# expand search grid based on motion modelfor move_x, move_y, move_cost in self.motion:node = self.Node(current.x + move_x,current.y + move_y,current.cost + move_cost, c_id)n_id = self.calc_index(node)if n_id in closed_set:continueif not self.verify_node(node):continueif n_id not in open_set:open_set[n_id] = node # Discover a new nodeelse:if open_set[n_id].cost >= node.cost:# This path is the best until now. record it!open_set[n_id] = noderx, ry = self.calc_final_path(goal_node, closed_set)return rx, rydef calc_final_path(self, goal_node, closed_set):# generate final courserx, ry = [self.calc_position(goal_node.x, self.min_x)], [self.calc_position(goal_node.y, self.min_y)]parent_index = goal_node.parent_indexwhile parent_index != -1:n = closed_set[parent_index]rx.append(self.calc_position(n.x, self.min_x))ry.append(self.calc_position(n.y, self.min_y))parent_index = n.parent_indexreturn rx, rydef calc_position(self, index, minp):pos = index * self.resolution + minpreturn posdef calc_xy_index(self, position, minp):return round((position - minp) / self.resolution)def calc_index(self, node):return node.y * self.x_width + node.xdef verify_node(self, node):px = self.calc_position(node.x, self.min_x)py = self.calc_position(node.y, self.min_y)if px < self.min_x:return Falseif py < self.min_y:return Falseif px >= self.max_x:return Falseif py >= self.max_y:return Falseif self.obstacle_map[node.x][node.y]:return Falsereturn Truedef calc_obstacle_map(self, ox, oy):''' 第1步:构建栅格地图 '''self.min_x = round(min(ox))self.min_y = round(min(oy))self.max_x = round(max(ox))self.max_y = round(max(oy))print("min_x:", self.min_x)print("min_y:", self.min_y)print("max_x:", self.max_x)print("max_y:", self.max_y)self.x_width = round((self.max_x - self.min_x) / self.resolution)self.y_width = round((self.max_y - self.min_y) / self.resolution)print("x_width:", self.x_width)print("y_width:", self.y_width)# obstacle map generation# 初始化地图self.obstacle_map = [[False for _ in range(self.y_width)]for _ in range(self.x_width)]# 设置障碍物for ix in range(self.x_width):x = self.calc_position(ix, self.min_x)for iy in range(self.y_width):y = self.calc_position(iy, self.min_y)for iox, ioy in zip(ox, oy):d = math.hypot(iox - x, ioy - y)if d <= self.robot_radius:self.obstacle_map[ix][iy] = Truebreak@staticmethoddef get_motion_model():# dx, dy, costmotion = [[1, 0, 1],[0, 1, 1],[-1, 0, 1],[0, -1, 1],[-1, -1, math.sqrt(2)],[-1, 1, math.sqrt(2)],[1, -1, math.sqrt(2)],[1, 1, math.sqrt(2)]]return motiondef main():# start and goal positionsx = -5.0 # [m]sy = -5.0 # [m]gx = 50.0 # [m]gy = 50.0 # [m]grid_size = 2.0 # [m]robot_radius = 1.0 # [m]# set obstacle positionsox, oy = [], []for i in range(-10, 60):ox.append(i)oy.append(-10.0)for i in range(-10, 60):ox.append(60.0)oy.append(i)for i in range(-10, 61):ox.append(i)oy.append(60.0)for i in range(-10, 61):ox.append(-10.0)oy.append(i)for i in range(-10, 40):ox.append(20.0)oy.append(i)for i in range(0, 40):ox.append(40.0)oy.append(60.0 - i)if show_animation: # pragma: no coverplt.plot(ox, oy, ".k")plt.plot(sx, sy, "og")plt.plot(gx, gy, "xb")plt.grid(True)plt.axis("equal")dijkstra = Dijkstra(ox, oy, grid_size, robot_radius)rx, ry = dijkstra.planning(sx, sy, gx, gy)if show_animation: # pragma: no coverplt.plot(rx, ry, "-r")plt.pause(0.01)plt.show()if __name__ == '__main__':main()先执行一下看看效果:
我们现在来详解一下:
我们从main函数开始:
# 1. 设置起点和终点sx = -5.0 # [m]sy = -5.0 # [m]gx = 50.0 # [m]gy = 50.0 # [m]# 2. 设置珊格的大小和机器人的半径grid_size = 2.0 # [m]robot_radius = 1.0 # [m]# 3. 设置障碍物的位置(图中的黑点就是)ox, oy = [], []# 3.1 设置外围的四堵墙 (-10,-10) --> (60,-10) 最下面的一条线for i in range(-10, 60):ox.append(i)oy.append(-10.0)# 3.1 设置外围的四堵墙 (60,-10) --> (60,60) 最右面的一条线for i in range(-10, 60):ox.append(60.0)oy.append(i)# 3.1 设置外围的四堵墙 (-10,60) --> (61,60) 最上面的一条线for i in range(-10, 61):ox.append(i)oy.append(60.0)# 3.1 设置外围的四堵墙 (-10,-10) --> (-10,61) 最左面的一条线for i in range(-10, 61):ox.append(-10.0)oy.append(i)# 3.2 障碍物for i in range(-10, 40):ox.append(20.0)oy.append(i)for i in range(0, 40):ox.append(40.0)oy.append(60.0 - i)# 4 画图 起点、终点、障碍物都画出来if show_animation: # pragma: no coverplt.plot(ox, oy, ".k")plt.plot(sx, sy, "og")plt.plot(gx, gy, "xb")plt.grid(True)plt.axis("equal")这段代码就设置了边框和障碍物区域并把他们可视化了:
就是我图中画的区域。
#生成了Dijkstra的对象 调用其中的方法(障碍物信息、珊格大小、机器人半径)dijkstra = Dijkstra(ox, oy, grid_size, robot_radius)生成了Dijkstra的对象。我们来看这个类的构造函数,进入一个类首先执行构造函数:
def __init__(self, ox, oy, resolution, robot_radius):"""Initialize map for planningox: x position list of Obstacles [m]oy: y position list of Obstacles [m]resolution: grid resolution [m]rr: robot radius[m]"""self.min_x = Noneself.min_y = Noneself.max_x = Noneself.max_y = Noneself.x_width = Noneself.y_width = Noneself.obstacle_map = None# 珊格大小self.resolution = resolution# 机器人半径self.robot_radius = robot_radius# 构建珊格地图self.calc_obstacle_map(ox, oy)self.motion = self.get_motion_model()我们先来看是怎么创建珊格地图的:
def calc_obstacle_map(self, ox, oy):''' 第1步:构建栅格地图 '''# 1. 获得地图的边界值self.min_x = round(min(ox))self.min_y = round(min(oy))self.max_x = round(max(ox))self.max_y = round(max(oy))print("min_x:", self.min_x)print("min_y:", self.min_y)print("max_x:", self.max_x)print("max_y:", self.max_y)# 2.计算x、y方向珊格个数self.x_width = round((self.max_x - self.min_x) / self.resolution)self.y_width = round((self.max_y - self.min_y) / self.resolution)print("x_width:", self.x_width)print("y_width:", self.y_width)# obstacle map generation# 3.初始化地图 都设置为false 表示还没有设置障碍物self.obstacle_map = [[False for _ in range(self.y_width)]for _ in range(self.x_width)]# 4.设置障碍物 遍历每一个栅格for ix in range(self.x_width):# 通过下标计算珊格位置x = self.calc_position(ix, self.min_x)for iy in range(self.y_width):y = self.calc_position(iy, self.min_y)# 遍历障碍物for iox, ioy in zip(ox, oy):# 计算障碍物到珊格的距离d = math.hypot(iox - x, ioy - y)# 膨胀障碍物 如果距离比机器人半径小 机器人不能通行if d <= self.robot_radius:# 设置为trueself.obstacle_map[ix][iy] = Truebreak首先我们获得了地图的边界值,算出了每一个方向上有多少珊格数量。
比如我们的长是100m(self.max_x - self.min_x = 100),珊格大小为3,那么我们每一行不就是有33个珊格啦~。
我们初始化obstacle_map,这个大小为珊格长 * 珊格宽的大小,我们将他们初始化为false表示这个地方没有障碍物。
然后我们遍历每一个珊格for ix in range(self.x_width)、for iy in range(self.y_width)。我们来看看calc_position这个方法做了什么。
def calc_position(self, index, minp):pos = index * self.resolution + minpreturn pos其实就计算了珊格所在位置的真实(x,y)坐标,比如我们的self.minx = 10,ix = 0,那么他的pos = 0 * 2 + 10 = 10,比如我们的self.minx = 10,ix = 1,那么他的pos = 1 * 2 + 10 = 12。我们遍历所有障碍物体的坐标,计算障碍物体(真实坐标)与这个机器人的距离,如果这个距离比机器人自身的大小小的话,我们将这个地方的珊格标志置为false表示有东西。
那么,在完成这个函数calc_obstacle_map时候,我们有了一张珊格地图,里面充斥着false和true,如果为true的话,那么机器人是过不去的,这块也就是设置成了障碍物区域。
我们接着往下看构造函数:
self.calc_obstacle_map(ox, oy)self.motion = self.get_motion_model()self.motion = self.get_motion_model()这段代码建立了机器人的运动模型和运动代价:
def get_motion_model():# dx, dy, costmotion = [[1, 0, 1], #x增加1,y不变 代价为1[0, 1, 1],[-1, 0, 1],[0, -1, 1],[-1, -1, math.sqrt(2)],[-1, 1, math.sqrt(2)],[1, -1, math.sqrt(2)],[1, 1, math.sqrt(2)]]return motion这里也就是机器人向左走(x+1,y+0)代价为1,斜着走代价为根号2。到此为止,我们构造函数讲解完了。我们返回主函数。
open_set这里开始正式进入路径规划了。传入的参数为起点坐标和终点坐标:
自动驾驶算法(一):Dijkstra算法讲解与代码实现我们先看下node类。
class Node:def __init__(self, x, y, cost, parent_index):self.x = x # index of gridself.y = y # index of gridself.cost = cost # g(n)self.parent_index = parent_index # index of previous Nodedef __str__(self):return str(self.x) + "," + str(self.y) + "," + str(self.cost) + "," + str(self.parent_index)首先执行构造函数,我们发现就是把珊格的(x,y)坐标(并非真实坐标是珊格的)还有cost(后文说)以及父节点的ID赋值了。(so easy)
我们在看一下calc_xy_index函数:
def calc_xy_index(self, position, minp):return round((position - minp) / self.resolution)它就是计算出真实世界的点点属于哪一个珊格的某一维度的坐标,我们举个例子:
self.calc_xy_index(sx, self.min_x) sx = 30 minx = 20这就代表我们的地图边界的 x 坐标为20,这个点的坐标x=30,我们用(30-20)/2 = 5,那么这个珊格坐标的x方向的坐标就是5。
start_node = self.Node(self.calc_xy_index(sx, self.min_x),self.calc_xy_index(sy, self.min_y), 0.0, -1) # round((position - minp) / self.resolution)goal_node = self.Node(self.calc_xy_index(gx, self.min_x),self.calc_xy_index(gy, self.min_y), 0.0, -1)因此,这段代码的含义就是我们计算出了起始和终止点的珊格坐标,并且将代价置为0,且他们的父节点为-1(没有父亲节点)。封装成了node。
下面进入算法部分,我们看流程图:
代码部分和流程图是一样的:
1.首先我们把起点放入openlist中:
# 设置openlist closelist 基于哈希表open_set, closed_set = dict(), dict() # key - value: hash表# 将startnode放进openset里面 索引为一维数组open_set[self.calc_index(start_node)] = start_node看一下calc_index函数:这里将珊格地图映射成了一个一维数组,返回数组的ID,类似C++中的二维数组降维。这里openset是一个字典,里面的key是珊格地图点的ID,value是这个珊格节点。
def calc_index(self, node):return node.y * self.x_width + node.x2.while True进入循环
while 1:2.1 取openlist cost最小的节点作为当前节点
c_id = min(open_set, key=lambda o: open_set[o].cost)current = open_set[c_id]2.2.1 判断当前是否为终点,如果是终点,如果是终点的话把终点的cost修改为当前点的cost值,且终点的父亲节点为当前点的父亲节点。
# 判断是否是终点if current.x == goal_node.x and current.y == goal_node.y:print("Find goal")# 当前节点的信息赋值给终点goal_node.parent_index = current.parent_indexgoal_node.cost = current.costbreak2.2.2 不是最终节点的话从openlist删除加入到closelist
# 把当前节点从openset里面删掉del open_set[c_id]# 加入到closed setclosed_set[c_id] = current2.3 遍历其9个邻接运动节点
for move_x, move_y, move_cost in self.motion:2.3.1 封装邻接节点
node = self.Node(current.x + move_x,current.y + move_y,current.cost + move_cost, c_id)这个点到邻接节点的移动就是 x +-( 1或-1或+根号2或-根号2),然后移动上下的话它的代价值需要+1,斜着移动需要 + 根号2,这样递归的进行我们就求出来所有点的代价值了,同样这个新走的点是通过我们这个点走过来的,因此新点的父节点就是我们这个点。
2.3.2 求当前节点的一维索引判断是否收录到closelist并判断是否可行,如果收录了,那么已经有最小路径了不需要我们再去处理了,还需要判断这个节点是否在珊格地图标记为false点上(珊格地图就是这么用的....)如果这个地方有障碍物那么我们也走不了。
# 求当前节点的keyn_id = self.calc_index(node)# 是否已经收录到close set里面if n_id in closed_set:continue# 邻接节点是否可行if not self.verify_node(node):continue2.3.3 如果不在openset里面我们就将她作为一个新节点加入,如果在openset比较值是否是最优更新,是否和之前的最优路径有重叠。
if n_id not in open_set:open_set[n_id] = node # Discover a new nodeelse:if open_set[n_id].cost >= node.cost:# This path is the best until now. record it!open_set[n_id] = node到这里我们的算法就结束了。我们迭代找到最终点后算法就break掉了~。
最后我们计算路径:
def calc_final_path(self, goal_node, closed_set):# generate final courserx, ry = [self.calc_position(goal_node.x, self.min_x)], [self.calc_position(goal_node.y, self.min_y)]parent_index = goal_node.parent_indexwhile parent_index != -1:n = closed_set[parent_index]rx.append(self.calc_position(n.x, self.min_x))ry.append(self.calc_position(n.y, self.min_y))parent_index = n.parent_indexreturn rx, ry我们将最终节点的珊格坐标还原成真实的三维坐标,并向前找他们的父亲节点直到起始节点(parent_index= -1),我们就出来这个路径了。
相关文章:
自动驾驶算法(一):Dijkstra算法讲解与代码实现
目录 0 本节关键词:栅格地图、算法、路径规划 1 Dijkstra算法详解 2 Dijkstra代码详解 0 本节关键词:栅格地图、算法、路径规划 1 Dijkstra算法详解 用于图中寻找最短路径。节点是地点,边是权重。 从起点开始逐步扩展,每一步为一…...
MS5910PA为行业内领先的可配置10bit到16bit分辨率的旋变数字转换器,可替代AD2S1210
MS5910PA 是一款可配置 10bit 到 16bit 分辨率的旋 变数字转换器。片上集成正弦波激励电路,正弦和余弦 允许输入峰峰值幅度为 2.3V 到 4.0V ,频率范围为 2kHz 至 20kHz 。 转换器可并行或串行输出角度和速度对应的 数字量。 MS5910PA 采…...
Random指定随机种子遇到的坑
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言指定随机种子出现的问题?总结 前言 业务中,之前有一个抽奖的需求,之初想让固定的奖品和玩家绑定一个固定的池子,…...
2023云栖大会:属于开发者的狂欢
就在10月31日这天,杭州云栖小镇热闹非凡,第八届云栖大会在杭州云栖小镇盛大举行。这次大会以“聚焦大模型与生成式AI”为主题,开发者们齐聚一堂,共同探讨前沿技术趋势,以及如何将这些技术应用到实际业务场景中。 当然…...
jsp 网上订餐Myeclipse开发mysql数据库web结构java编程计算机网页项目
选题目的 本设计课题为网上订餐系统设计与实现,提供无纸化点餐、支付,实现点餐快捷,方便管理。餐厅电子化是目前的潮流和趋势,大多数企业都将公司内部运营流程电子化。网上订餐管理系统应运而生,能够有效提高公司的管…...
优化大表分页查询性能:大表LIMIT 1000000, 10该怎么优化?
在处理大数据量的MySQL表时,我们经常会遇到一个问题:当我们尝试使用LIMIT语句进行分页查询时,性能会随着偏移量的增加而显著下降。例如,SELECT * FROM table LIMIT 1000000, 10 这样的查询可能会非常慢。那么,我们应该…...
ubuntu PX4 vscode stlink debug设置
硬件 stlink holybro debug板 pixhawk4 安装openocd 官方文档,但是第一步安装建议从源码安装,bug少很多 github链接 编译安装,参考 ./bootstrap (when building from the git repository)./configure [options]makesudo make install安装后…...
Flask的一种启动方式和三种托管方式
1. 原生启动 Flask 支持使用原生的 app.run() 方法来启动应用程序。这种方法是最简单、最基本的启动方式,适用于开发环境和小型应用程序。 from flask import Flaskapp Flask(__name__)app.route(/) def hello_world():return Hello, World!if __name__ __main__…...
cudnn too short
原因是libcudnn.so为软链接,相当于快捷键,但是没有映射到真正的libcudnn.so.8.9.5上 cd /usr/local/cuda-11.6/lib64 ln -s libcudnn.so.8.9.5 libcudnn.so.8...
01、SpringBoot + MyBaits-Plus 集成微信支付 -->项目搭建
目录 SpringBoot MyBaits-Plus 集成微信支付 之 项目搭建1、创建boot项目2、引入Swagger作用:2-1、引入依赖2-2、写配置文件进行测试2-3、访问Swagger页面2-4、注解优化显示 3、定义统一结果作用:3-1、引入lombok依赖3-2、写个统一结果的类-->RR类的…...
Linux 性能调优之网络优化
写在前面 考试整理相关笔记分享一些 Linux 中网络内核参数调优的笔记理解不足小伙伴帮忙指正 对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃…...
RT-Thread系统使用常见问题处理记录
1.使用telnet连接系统时发送help指令显示不全的问题。 原因:telnet发送缓存太小。 解决办法:更改agile_telnet软件包里Set agile_telnet tx buffer size的大小。 2.使用Paho MQTT软件包过一段时间报错hard fault on thread: mqtt0 解决办法࿱…...
优先队列----数据结构
概念 不知道你玩过英雄联盟吗?英雄联盟里面的防御塔会攻击离自己最近的小兵,但是如果有炮车兵在塔内,防御塔会优先攻击炮车(因为炮车的威胁性更大),只有没有兵线在塔内时,防御塔才会攻击英雄。…...
nginx项目部署教程
nginx项目部署教程 1. 项目部署介绍 当我们的项目开发完毕后,我们需要将项目打包、部署到服务器上,供用户来使用。 目前,常见的部署方式有两种: 后端部署 前后端分离部署 1-1 后端部署 这是最古老的部署方式,也是…...
资源限流 + 本地分布式多重锁——高并发性能挡板,隔绝无效流量请求
前言 在高并发分布式下,我们往往采用分布式锁去维护一个同步互斥的业务需求,但是大家细想一下,在一些高TPS的业务场景下,让这些请求全部卡在获取分布式锁,这会造成什么问题? 瞬时高并发压垮系统 众所周知…...
day52【子序列】300.最长递归子序列 674.最长连续递增序列 718.最长重复子数组
文章目录 300.最长递增子序列674.最长连续递增序列718.最长重复子数组 300.最长递增子序列 题目链接:力扣链接 讲解链接:代码随想录链接 题意:给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列 是由数组派生而…...
计算机视觉 计算机视觉识别是什么?
计算机视觉识别(Computer Vision Recognition)是计算机科学和人工智能领域中的一个重要分支,它致力于使计算机系统能够模拟和理解人类视觉的过程,从而能够自动识别、分析和理解图像或视频中的内容。这一领域的发展旨在让计算机具备…...
Make.com实现多个APP应用的自动化的入门指南
Make.com是一款基于云的自动化平台,可帮助用户将多个应用程序连接在一起,并通过设置自动化流程来简化日常任务。Make.com提供丰富的API集成,支持连接各种流行的应用程序,包括社交媒体、电子商务、CRM等。 使用Make.com实现多个AP…...
LLMs之HFKR:HFKR(基于大语言模型实现异构知识融合的推荐算法)的简介、原理、性能、实现步骤、案例应用之详细攻略
LLMs之HFKR:HFKR(基于大语言模型实现异构知识融合的推荐算法)的简介、原理、性能、实现步骤、案例应用之详细攻略 目录 HFKR的简介 异构知识融合:一种基于LLM的个性化推荐新方法...
多模态 多引擎 超融合 新生态!2023亚信科技AntDB数据库8.0产品发布
9月20日,以“多模态 多引擎 超融合 新生态”为主题的亚信科技AntDB数据库8.0产品发布会成功举办,从技术和生态两个角度全方位展示了AntDB数据库第8次大型能力升级和生态建设成果。浙江移动、用友、麒麟软件、华录高诚、金云智联等行业伙伴及业界专家共同…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...
HTTPS证书一年多少钱?
HTTPS证书作为保障网站数据传输安全的重要工具,成为众多网站运营者的必备选择。然而,面对市场上种类繁多的HTTPS证书,其一年费用究竟是多少,又受哪些因素影响呢? 首先,HTTPS证书通常在PinTrust这样的专业平…...
高端性能封装正在突破性能壁垒,其芯片集成技术助力人工智能革命。
2024 年,高端封装市场规模为 80 亿美元,预计到 2030 年将超过 280 亿美元,2024-2030 年复合年增长率为 23%。 细分到各个终端市场,最大的高端性能封装市场是“电信和基础设施”,2024 年该市场创造了超过 67% 的收入。…...








