自动驾驶算法(五):Informed RRT*算法讲解与代码实现(基于采样的路径规划) 与比较

news2024/11/25 2:29:51

目录

1 RRT*与Informed RRT*

2 Informed RRT*代码解析

3 完整代码

4 算法比较


1 RRT*与Informed RRT*

        上篇博客我们介绍了RRT*算法:我们在找到一个路径以后我们还会反复的搜索。

        Informed RRT*算法提出的动机(motivation)是能否增加渐近最优的速度呢?

        根据这篇论文的思想:Informed RRT*: Optimal Sampling-based Path Planning Focused via Direct Sampling of an Admissible Ellipsoidal Heuristic。

        我们通过限制采样范围来增加渐进最优的速度。也就是我们在找到路径后限制采样的范围(椭圆),它的长轴就是我们找到路径的cbest,短轴就是如上图,cmin是起点和终点连起来的距离。感兴趣的同学可以去看一下论文。通过cbest越来越小采样的范围也就越来越小。最后我们就会找到路径。我们看一下椭圆是怎么找的,和RRT*相比仅仅改变了采样的Sample函数:

2 Informed RRT*代码解析

        start_time = time.time()
        self.start = Node(start[0], start[1])
        self.goal = Node(goal[0], goal[1])
        self.node_list = [self.start]
        # max length we expect to find in our 'informed' sample space,
        # starts as infinite
        cBest = float('inf')
        path = None

        # Computing the sampling space
        cMin = math.sqrt(pow(self.start.x - self.goal.x, 2)
                         + pow(self.start.y - self.goal.y, 2))
        xCenter = np.array([[(self.start.x + self.goal.x) / 2.0],
                            [(self.start.y + self.goal.y) / 2.0], [0]])
        a1 = np.array([[(self.goal.x - self.start.x) / cMin],
                       [(self.goal.y - self.start.y) / cMin], [0]])

        e_theta = math.atan2(a1[1], a1[0])

        这里先初始化cbest为无穷大,将path置为空路径。求出起始点和终点的距离cMin

        Xcenter创建了一个 numpy 数组 xCenter,其中包含了 self.start(导航起始点) 和 self.goal(导航终止点) 之间的中心点的 x 和 y 坐标,以及一个零。

        a1 = np.array([[(self.goal.x - self.start.x) / cMin], [(self.goal.y - self.start.y) / cMin], [0]]): 创建了一个 numpy 数组 a1,它表示了从 self.start 指向 self.goal 的单位向量,除以距离 cMin

        e_theta = math.atan2(a1[1], a1[0]): 使用 math.atan2 计算了单位向量 a1 与 x 轴之间的角度 e_theta(以弧度表示)。

        用数学公式表示如下:

        C = np.array([[math.cos(e_theta), -math.sin(e_theta), 0],
                      [math.sin(e_theta), math.cos(e_theta),  0],
                      [0,                 0,                  1]])

        和RRT与RRT*相比,只改变了采样函数,我们看采样函数:

    def informed_sample(self, cMax, cMin, xCenter, C):
        if cMax < float('inf'):
            r = [cMax / 2.0,
                 math.sqrt(cMax ** 2 - cMin ** 2) / 2.0,
                 math.sqrt(cMax ** 2 - cMin ** 2) / 2.0]
            L = np.diag(r)
            xBall = self.sample_unit_ball()
            rnd = np.dot(np.dot(C, L), xBall) + xCenter
            rnd = [rnd[(0, 0)], rnd[(1, 0)]]
        else:
            rnd = self.sample()

        return rnd

    def sample_unit_ball():
        a = random.random()
        b = random.random()

        if b < a:
            a, b = b, a

        sample = (b * math.cos(2 * math.pi * a / b),
                  b * math.sin(2 * math.pi * a / b))
        return np.array([[sample[0]], [sample[1]], [0]])

        这段代码定义了一个名为 `sample_unit_ball` 的函数,它用于生成一个单位球内的随机点。

具体来说,代码中的操作如下:

1. `a = random.random()`: 生成一个在 [0, 1) 范围内的随机浮点数并将其赋给变量 `a`。

2. `b = random.random()`: 同样地,生成一个在 [0, 1) 范围内的随机浮点数并将其赋给变量 `b`。

3. `if b < a: a, b = b, a`: 如果 `b` 小于 `a`,则交换它们的值,确保 `a` 始终大于等于 `b`。

4. `sample = (b * math.cos(2 * math.pi * a / b), b * math.sin(2 * math.pi * a / b))`: 这里使用生成的随机数 `a` 和 `b` 计算了一个点 `sample`,它位于极坐标系中的角度 `2πa/b` 处,并且距离原点的距离为 `b`。

5. `return np.array([[sample[0]], [sample[1]], [0]])`: 将 `sample` 转换为一个列向量,并添加一个零作为第三个元素,最终返回一个二维的列向量。

总的来说,这个函数用于在单位球内生成一个随机点,它的坐标通过随机生成的参数 `a` 和 `b` 以及一些三角函数计算得到。

        rnd = np.dot(np.dot(C, L), xBall) + xCenter这里是先把单位圆压缩成椭圆,得到新采样的点。

3 完整代码

import copy
import math
import random
import time

import matplotlib.pyplot as plt
from scipy.spatial.transform import Rotation as Rot
import numpy as np

show_animation = True


class RRT:

    # randArea采样范围[-2--18] obstacleList设置的障碍物 maxIter最大迭代次数 expandDis采样步长为2.0 goalSampleRate 以10%的概率将终点作为采样点
    def __init__(self, obstacleList, randArea,
                 expandDis=2.0, goalSampleRate=10, maxIter=200):

        self.start = None
        self.goal = None
        self.min_rand = randArea[0]
        self.max_rand = randArea[1]
        self.expand_dis = expandDis
        self.goal_sample_rate = goalSampleRate
        self.max_iter = maxIter
        self.obstacle_list = obstacleList
        # 存储RRT树
        self.node_list = None

    # start、goal 起点终点坐标
    def rrt_planning(self, start, goal, animation=True):
        start_time = time.time()
        self.start = Node(start[0], start[1])
        self.goal = Node(goal[0], goal[1])
        # 将起点加入node_list作为树的根结点
        self.node_list = [self.start]
        path = None

        for i in range(self.max_iter):
            # 进行采样
            rnd = self.sample()
            # 取的距离采样点最近的节点下标
            n_ind = self.get_nearest_list_index(self.node_list, rnd)
            # 得到最近节点
            nearestNode = self.node_list[n_ind]

            # 将Xrandom和Xnear连线方向作为生长方向
            # math.atan2() 函数接受两个参数,分别是 y 坐标差值和 x 坐标差值。它返回的值是以弧度表示的角度,范围在 -π 到 π 之间。这个角度表示了从 nearestNode 指向 rnd 的方向。
            theta = math.atan2(rnd[1] - nearestNode.y, rnd[0] - nearestNode.x)
            # 生长 : 输入参数为角度、下标、nodelist中最近的节点  得到生长过后的节点
            newNode = self.get_new_node(theta, n_ind, nearestNode)
            # 检查是否有障碍物 传入参数为新生城路径的两个节点
            noCollision = self.check_segment_collision(newNode.x, newNode.y, nearestNode.x, nearestNode.y)
            if noCollision:
                # 没有碰撞把新节点加入到树里面
                self.node_list.append(newNode)
                if animation:
                    self.draw_graph(newNode, path)

                # 是否到终点附近
                if self.is_near_goal(newNode):
                    # 是否这条路径与障碍物发生碰撞
                    if self.check_segment_collision(newNode.x, newNode.y,
                                                    self.goal.x, self.goal.y):
                        lastIndex = len(self.node_list) - 1
                        # 找路径
                        path = self.get_final_course(lastIndex)
                        pathLen = self.get_path_len(path)
                        print("current path length: {}, It costs {} s".format(pathLen, time.time()-start_time))

                        if animation:
                            self.draw_graph(newNode, path)
                        return path

    def rrt_star_planning(self, start, goal, animation=True):
        start_time = time.time()
        self.start = Node(start[0], start[1])
        self.goal = Node(goal[0], goal[1])
        self.node_list = [self.start]
        path = None
        lastPathLength = float('inf')

        for i in range(self.max_iter):
            rnd = self.sample()
            n_ind = self.get_nearest_list_index(self.node_list, rnd)
            nearestNode = self.node_list[n_ind]

            # steer
            theta = math.atan2(rnd[1] - nearestNode.y, rnd[0] - nearestNode.x)
            newNode = self.get_new_node(theta, n_ind, nearestNode)

            noCollision = self.check_segment_collision(newNode.x, newNode.y, nearestNode.x, nearestNode.y)
            if noCollision:
                nearInds = self.find_near_nodes(newNode)
                newNode = self.choose_parent(newNode, nearInds)

                self.node_list.append(newNode)
                # 重联
                self.rewire(newNode, nearInds)

                if animation:
                    self.draw_graph(newNode, path)

                if self.is_near_goal(newNode):
                    if self.check_segment_collision(newNode.x, newNode.y,
                                                    self.goal.x, self.goal.y):
                        lastIndex = len(self.node_list) - 1

                        tempPath = self.get_final_course(lastIndex)
                        tempPathLen = self.get_path_len(tempPath)
                        if lastPathLength > tempPathLen:
                            path = tempPath
                            lastPathLength = tempPathLen
                            print("current path length: {}, It costs {} s".format(tempPathLen, time.time()-start_time))

        return path

    def informed_rrt_star_planning(self, start, goal, animation=True):
        start_time = time.time()
        self.start = Node(start[0], start[1])
        self.goal = Node(goal[0], goal[1])
        self.node_list = [self.start]
        # max length we expect to find in our 'informed' sample space,
        # starts as infinite
        cBest = float('inf')
        path = None

        # Computing the sampling space
        cMin = math.sqrt(pow(self.start.x - self.goal.x, 2)
                         + pow(self.start.y - self.goal.y, 2))
        xCenter = np.array([[(self.start.x + self.goal.x) / 2.0],
                            [(self.start.y + self.goal.y) / 2.0], [0]])
        a1 = np.array([[(self.goal.x - self.start.x) / cMin],
                       [(self.goal.y - self.start.y) / cMin], [0]])

        e_theta = math.atan2(a1[1], a1[0])

        # 论文方法求旋转矩阵(2选1)
        # first column of identity matrix transposed
        # id1_t = np.array([1.0, 0.0, 0.0]).reshape(1, 3)
        # M = a1 @ id1_t
        # U, S, Vh = np.linalg.svd(M, True, True)
        # C = np.dot(np.dot(U, np.diag(
        #     [1.0, 1.0, np.linalg.det(U) * np.linalg.det(np.transpose(Vh))])),
        #            Vh)

        # 直接用二维平面上的公式(2选1)
        C = np.array([[math.cos(e_theta), -math.sin(e_theta), 0],
                      [math.sin(e_theta), math.cos(e_theta),  0],
                      [0,                 0,                  1]])

        for i in range(self.max_iter):
            # Sample space is defined by cBest
            # cMin is the minimum distance between the start point and the goal
            # xCenter is the midpoint between the start and the goal
            # cBest changes when a new path is found

            rnd = self.informed_sample(cBest, cMin, xCenter, C)
            n_ind = self.get_nearest_list_index(self.node_list, rnd)
            nearestNode = self.node_list[n_ind]

            # steer
            theta = math.atan2(rnd[1] - nearestNode.y, rnd[0] - nearestNode.x)
            newNode = self.get_new_node(theta, n_ind, nearestNode)

            noCollision = self.check_segment_collision(newNode.x, newNode.y, nearestNode.x, nearestNode.y)
            if noCollision:
                nearInds = self.find_near_nodes(newNode)
                newNode = self.choose_parent(newNode, nearInds)

                self.node_list.append(newNode)
                self.rewire(newNode, nearInds)

                if self.is_near_goal(newNode):
                    if self.check_segment_collision(newNode.x, newNode.y,
                                                    self.goal.x, self.goal.y):
                        lastIndex = len(self.node_list) - 1
                        tempPath = self.get_final_course(lastIndex)
                        tempPathLen = self.get_path_len(tempPath)
                        if tempPathLen < cBest:
                            path = tempPath
                            cBest = tempPathLen
                            print("current path length: {}, It costs {} s".format(tempPathLen, time.time()-start_time))
            if animation:
                self.draw_graph_informed_RRTStar(xCenter=xCenter,
                                                cBest=cBest, cMin=cMin,
                                                e_theta=e_theta, rnd=rnd, path=path)

        return path

    def sample(self):
        # 取得1-100的随机数,如果比10大的话(以10%的概率取到终点)
        if random.randint(0, 100) > self.goal_sample_rate:
            # 在空间里随机采样一个点
            rnd = [random.uniform(self.min_rand, self.max_rand), random.uniform(self.min_rand, self.max_rand)]
        else:  # goal point sampling
            # 终点作为采样点
            rnd = [self.goal.x, self.goal.y]
        return rnd

    def choose_parent(self, newNode, nearInds):
        # 圈里是否有候选节点
        if len(nearInds) == 0:
            return newNode

        dList = []
        for i in nearInds:
            dx = newNode.x - self.node_list[i].x
            dy = newNode.y - self.node_list[i].y
            d = math.hypot(dx, dy)
            theta = math.atan2(dy, dx)
            # 检测是否碰到障碍物
            if self.check_collision(self.node_list[i], theta, d):
                # 计算距离
                dList.append(self.node_list[i].cost + d)
            else:
                # 无穷大
                dList.append(float('inf'))

        # 找到路径最小的的点 父节点
        minCost = min(dList)
        minInd = nearInds[dList.index(minCost)]

        if minCost == float('inf'):
            print("min cost is inf")
            return newNode

        newNode.cost = minCost
        newNode.parent = minInd

        return newNode

    def find_near_nodes(self, newNode):
        n_node = len(self.node_list)
        # 动态变化 搜索到越后面的话半径越小
        r = 50.0 * math.sqrt((math.log(n_node) / n_node))
        # 找到节点
        d_list = [(node.x - newNode.x) ** 2 + (node.y - newNode.y) ** 2
                  for node in self.node_list]
        # 比半径小
        near_inds = [d_list.index(i) for i in d_list if i <= r ** 2]
        return near_inds

    def informed_sample(self, cMax, cMin, xCenter, C):
        if cMax < float('inf'):
            r = [cMax / 2.0,
                 math.sqrt(cMax ** 2 - cMin ** 2) / 2.0,
                 math.sqrt(cMax ** 2 - cMin ** 2) / 2.0]
            L = np.diag(r)
            xBall = self.sample_unit_ball()
            rnd = np.dot(np.dot(C, L), xBall) + xCenter
            rnd = [rnd[(0, 0)], rnd[(1, 0)]]
        else:
            rnd = self.sample()

        return rnd

    @staticmethod
    def sample_unit_ball():
        a = random.random()
        b = random.random()

        if b < a:
            a, b = b, a

        sample = (b * math.cos(2 * math.pi * a / b),
                  b * math.sin(2 * math.pi * a / b))
        return np.array([[sample[0]], [sample[1]], [0]])

    @staticmethod
    def get_path_len(path):
        pathLen = 0
        for i in range(1, len(path)):
            node1_x = path[i][0]
            node1_y = path[i][1]
            node2_x = path[i - 1][0]
            node2_y = path[i - 1][1]
            pathLen += math.sqrt((node1_x - node2_x)
                                 ** 2 + (node1_y - node2_y) ** 2)

        return pathLen

    @staticmethod
    def line_cost(node1, node2):
        return math.sqrt((node1.x - node2.x) ** 2 + (node1.y - node2.y) ** 2)

    @staticmethod
    def get_nearest_list_index(nodes, rnd):
        # 遍历所有节点 计算采样点和节点的距离
        dList = [(node.x - rnd[0]) ** 2
                 + (node.y - rnd[1]) ** 2 for node in nodes]
        # 获得最近的距离所对应的索引
        minIndex = dList.index(min(dList))
        return minIndex

    def get_new_node(self, theta, n_ind, nearestNode):
        newNode = copy.deepcopy(nearestNode)

        # 坐标
        newNode.x += self.expand_dis * math.cos(theta)
        newNode.y += self.expand_dis * math.sin(theta)
        # 代价
        newNode.cost += self.expand_dis
        # 父亲节点
        newNode.parent = n_ind
        return newNode

    def is_near_goal(self, node):
        # 计算距离
        d = self.line_cost(node, self.goal)
        if d < self.expand_dis:
            return True
        return False

    def rewire(self, newNode, nearInds):
        n_node = len(self.node_list)
        # 新节点 和圆圈的候选点
        for i in nearInds:
            nearNode = self.node_list[i]

            # 以newnode作为父节点 计算两条节点之间的距离
            d = math.sqrt((nearNode.x - newNode.x) ** 2
                          + (nearNode.y - newNode.y) ** 2)

            s_cost = newNode.cost + d

            if nearNode.cost > s_cost:
                theta = math.atan2(newNode.y - nearNode.y,
                                   newNode.x - nearNode.x)
                if self.check_collision(nearNode, theta, d):
                    nearNode.parent = n_node - 1
                    nearNode.cost = s_cost

    @staticmethod
    def distance_squared_point_to_segment(v, w, p):
        # Return minimum distance between line segment vw and point p
        if np.array_equal(v, w):
            return (p - v).dot(p - v)  # v == w case
        l2 = (w - v).dot(w - v)  # i.e. |w-v|^2 -  avoid a sqrt
        # Consider the line extending the segment,
        # parameterized as v + t (w - v).
        # We find projection of point p onto the line.
        # It falls where t = [(p-v) . (w-v)] / |w-v|^2
        # We clamp t from [0,1] to handle points outside the segment vw.
        t = max(0, min(1, (p - v).dot(w - v) / l2))
        projection = v + t * (w - v)  # Projection falls on the segment
        return (p - projection).dot(p - projection)

    def check_segment_collision(self, x1, y1, x2, y2):
        # 遍历所有的障碍物
        for (ox, oy, size) in self.obstacle_list:
            dd = self.distance_squared_point_to_segment(
                np.array([x1, y1]),
                np.array([x2, y2]),
                np.array([ox, oy]))
            if dd <= size ** 2:
                return False  # collision
        return True

    def check_collision(self, nearNode, theta, d):
        tmpNode = copy.deepcopy(nearNode)
        end_x = tmpNode.x + math.cos(theta) * d
        end_y = tmpNode.y + math.sin(theta) * d
        return self.check_segment_collision(tmpNode.x, tmpNode.y, end_x, end_y)

    def get_final_course(self, lastIndex):
        path = [[self.goal.x, self.goal.y]]
        while self.node_list[lastIndex].parent is not None:
            node = self.node_list[lastIndex]
            path.append([node.x, node.y])
            lastIndex = node.parent
        path.append([self.start.x, self.start.y])
        return path

    def draw_graph_informed_RRTStar(self, xCenter=None, cBest=None, cMin=None, e_theta=None, rnd=None, path=None):
        plt.clf()
        # 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 rnd is not None:
            plt.plot(rnd[0], rnd[1], "^k")
            if cBest != float('inf'):
                self.plot_ellipse(xCenter, cBest, cMin, e_theta)

        for node in self.node_list:
            if node.parent is not None:
                if node.x or node.y is not None:
                    plt.plot([node.x, self.node_list[node.parent].x], [
                        node.y, self.node_list[node.parent].y], "-g")

        for (ox, oy, size) in self.obstacle_list:
            plt.plot(ox, oy, "ok", ms=30 * size)

        if path is not None:
            plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r')

        plt.plot(self.start.x, self.start.y, "xr")
        plt.plot(self.goal.x, self.goal.y, "xr")
        plt.axis([-2, 18, -2, 15])
        plt.grid(True)
        plt.pause(0.01)

    @staticmethod
    def plot_ellipse(xCenter, cBest, cMin, e_theta):  # pragma: no cover

        a = math.sqrt(cBest ** 2 - cMin ** 2) / 2.0
        b = cBest / 2.0
        angle = math.pi / 2.0 - e_theta
        cx = xCenter[0]
        cy = xCenter[1]
        t = np.arange(0, 2 * math.pi + 0.1, 0.1)
        x = [a * math.cos(it) for it in t]
        y = [b * math.sin(it) for it in t]
        rot = Rot.from_euler('z', -angle).as_matrix()[0:2, 0:2]
        fx = rot @ np.array([x, y])
        px = np.array(fx[0, :] + cx).flatten()
        py = np.array(fx[1, :] + cy).flatten()
        plt.plot(cx, cy, "xc")
        plt.plot(px, py, "--c")

    def draw_graph(self, rnd=None, path=None):
        plt.clf()
        # 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 rnd is not None:
            plt.plot(rnd.x, rnd.y, "^k")

        for node in self.node_list:
            if node.parent is not None:
                if node.x or node.y is not None:
                    plt.plot([node.x, self.node_list[node.parent].x], [
                        node.y, self.node_list[node.parent].y], "-g")

        for (ox, oy, size) in self.obstacle_list:
            # self.plot_circle(ox, oy, size)
            plt.plot(ox, oy, "ok", ms=30 * size)

        plt.plot(self.start.x, self.start.y, "xr")
        plt.plot(self.goal.x, self.goal.y, "xr")

        if path is not None:
            plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r')

        plt.axis([-2, 18, -2, 15])
        plt.grid(True)
        plt.pause(0.01)


class Node:

    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.cost = 0.0
        self.parent = None


def main():
    print("Start rrt planning")

    # create obstacles
    # obstacleList = [
    #     (3,  3,  1.5),
    #     (12, 2,  3),
    #     (3,  9,  2),
    #     (9,  11, 2),
    # ]

    # 设置障碍物 (圆点、半径)
    obstacleList = [(5, 5, 1), (3, 6, 2), (3, 8, 2), (3, 10, 2), (7, 5, 2),
                    (9, 5, 2), (8, 10, 1)]

    # Set params
    # 采样范围 设置的障碍物 最大迭代次数
    rrt = RRT(randArea=[-2, 18], obstacleList=obstacleList, maxIter=200)
    # 传入的是起点和终点
    #path = rrt.rrt_planning(start=[0, 0], goal=[15, 12], animation=show_animation)
    #path = rrt.rrt_star_planning(start=[0, 0], goal=[15, 12], animation=show_animation)
    path = rrt.informed_rrt_star_planning(start=[0, 0], goal=[15, 12], animation=show_animation)
    print("Done!!")

    if show_animation and path:
        plt.show()


if __name__ == '__main__':
    main()

4 算法比较

        RRT:路径较差,非最优,在本例程中为6ms。

        RRT*:路径渐进最优,在本例程中为34ms。

        Informed RRT*:路径渐进最优,在本例程中为109ms。

        看官姥爷看自己需求用奥。

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

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

相关文章

【腾讯云HAI域探秘】速通腾讯云HAI

速览HAI 产品简介 腾讯云高性能应用服务(Hyper Application lnventor&#xff0c;HA)&#xff0c;是一款面向 Al、科学计算的 GPU 应用服务产品&#xff0c;为开发者量身打造的澎湃算力平台。无需复杂配置&#xff0c;便可享受即开即用的GPU云服务体验。在 HA] 中&#xff0c;…

3000 台 Apache ActiveMQ 服务器易受 RCE 攻击

超过三千个暴露在互联网上的 Apache ActiveMQ 服务器容易受到最近披露的关键远程代码执行 (RCE) 漏洞的影响。 Apache ActiveMQ 是一个可扩展的开源消息代理&#xff0c;可促进客户端和服务器之间的通信&#xff0c;支持 Java 和各种跨语言客户端以及许多协议&#xff0c;包括…

Sentinel热点参数限流动

什么是热点 限流是统计访问某个资源的所有请求&#xff0c;判断是否超过QPS阈值。而热点参数限流是分别统计参数值相同的请求&#xff0c;判断是否超过QPS阈值。 何为热点&#xff1f;热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据&am…

关于Intel Press出版的《Bedyong BIOS》第2版的观后感

文章目录 此书的背景UEFI运行时DXE基础CPU架构协议PCI协议UEFI驱动的初始化串口DXE驱动示例 《Beyond BIOS》首先介绍一个简单的UEFI应用程序模块&#xff0c;用于展示UEFI应用程序的行为。作者为Waldo。该模块名为“InitializeHelloApplication”&#xff0c;它接受两个参数&a…

云栖大会,到底有些啥?

引言&#xff1a;10月31日至11月2日&#xff0c;2023云栖大会在杭州云栖小镇召开。小枣君去了现场&#xff0c;拍了一些照片&#xff0c;特来给大家做一个图文汇报。 云栖大会的前身&#xff0c;是2009年开始举办的地方网站峰会。2011年&#xff0c;这个峰会演变成阿里云开发者…

Linux的历史与环境

目录 Linux的背景介绍 Linux的时代背景-硅谷模式 计算机发展 UNIX发展历史 Linux诞生的偶然与必然 Linux开源 Linux发行版本 搭建Linux的环境 1.直接安装在物理机上 2.使用虚拟机软件 3.使用云服务器 &#xff08;1&#xff09;购买云服务器 &#xff08;2&#x…

docker是干什么的

很多朋友刚接触docker&#xff0c;不知道docker做什么&#xff0c; 这里白眉大叔给大家普及一下 docker的知识以及docker和虚拟机的区别。 你可以这样认为&#xff0c;docker 就是 打包应用程序的工具。 怎么理解这个工具呢&#xff1f; 1-如何理解docker 这个打包工具&#x…

作为一个初学者,该如何入门大模型?

在生成式 AI 盛行的当下&#xff0c;你是否被这种技术所折服&#xff0c;例如输入一段简简单单的文字&#xff0c;转眼之间&#xff0c;一幅精美的图片&#xff0c;又或者是文笔流畅的文字就展现在你的面前。 相信很多人有这种想法&#xff0c;认为生成式 AI 深不可测&#xf…

选择适合你的办公桌:提高工作效率的关键

​在如今的数字时代&#xff0c;越来越多的人将办公桌移到家里或办公室。但是&#xff0c;如何选择适合你的办公桌可能是个挑战。不同的工作需要和工作空间大小会影响你的选择。下面是一些简单的建议&#xff0c;帮助你找到适合你的办公桌&#xff0c;提高工作效率。 首先&…

世微 平均电流型降压恒流驱动器 电动摩托车LED灯小钢炮驱动IC AP5218

1&#xff0c;来源&#xff1a;深圳市世微半导体有限公司 2&#xff0c;产品描述 AP5218 是一款 PWM工作模式, 高效率、外 围简单、内置功率管&#xff0c;适用于5V&#xff5e;100V输入的高 精度降压 LED 恒流驱动芯片。输出最大功率可达 15W&#xff0c;最大电流 1.5A。AP5…

Leetcode—2512.奖励最顶尖的K名学生【中等】

2023每日刷题&#xff08;十九&#xff09; Leetcode—2512.奖励最顶尖的K名学生 哈希表stringstream排序算法思想 实现代码 class Solution { public:vector<int> topStudents(vector<string>& positive_feedback, vector<string>& negative_feed…

MySQL中如何书写update避免锁表

1. 什么是MySQL锁表&#xff1f; MySQL锁表是指在对某个数据表进行读写操作时&#xff0c;为了保证数据的一致性和完整性&#xff0c;系统会对该数据表进行锁定&#xff0c;防止其他用户对该表进行操作。 2. 为什么会出现锁表&#xff1f; 当多个用户同时对同一个数据表进行…

(附源码)基于springboot校园自媒体信息服务平台-计算机毕设 84565

springboot校园自媒体信息服务平台 目 录 摘要 1 绪论 1.1课题意义 1.2开发现状 1.3系统开发技术的特色 1.4springboot框架介绍 1.5论文结构与章节安排 2 2校园自媒体信息服务平台系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1数据增加流程 2.3.2数据修改流程 2…

一文搞定 Linux 中 Python 环境/版本管理

Python 的环境/版本管理实在是依托答辩&#xff0c;感觉不如 Node.js。 尤其是在 Linux 环境下&#xff0c;多数发行版的系统组件、工具依赖自带的 Python&#xff0c;折腾系统自带的 Python 环境时&#xff0c;一个搞不好就会把整个系统干掉。 同时&#xff0c;研究安全的小伙…

前端使用firebase配置第三方登录介绍(谷歌登录,facebook登录等)

参考文档 点此处去 firebase 官网点此处去 web端的谷歌登录文档 实现 首先注册一个账号登录firebase&#xff08;可以使用谷歌账号登录&#xff09; 然后创建项目&#xff08;走默认配置就行了&#xff09; 添加应用&#xff08;走默认配置&#xff09;&#xff0c;如图所…

SpringBoot-SpringTask定时任务

文章目录 Spring Task 介绍cron 表达式Spring Task 入门案例 Spring Task 介绍 Spring Task 是 Spring 框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑。 作用&#xff1a;定时自动执行某段 Java 代码 应用场景&#xff1a; 信用卡每月还款提醒…

【java学习—十二】文件字节流(2)

文章目录 1. 文件字节输入流2. 文件字节输出流3. 练习 1. 文件字节输入流 举例&#xff1a; tt1.txt文件内容为&#xff1a;aaaa package day12;import java.io.FileInputStream;public class Test1 {public static void main(String[] args) {Test1.testFileInputStream();}…

【Vue3+Vite+bwip-js库】 生成DataMatrix码

前提条件 已存在的vue3vite架构前端项目对二维码分类有一定的了解 生成的码的样式如下&#xff08;DataMatrix&#xff09; 该二维码容量如下 详情见&#xff1a;DataMatrix介绍 Vue3Vite 导入 bwip-js生成DataMatrix 1. 安装 npm install bwip-js --save2. 引入使用 <…

「视频编码软件」Media Encoder(Me) 2024 Mac/win中文版下载安装

Adobe Media Encoder(Me) 2024是一款专业的视频编码工具&#xff0c;它可以将各种视频格式进行转换、压缩和编码&#xff0c;以满足不同媒体平台和设备的需求。 以下是 Media Encoder 2023 的主要功能和新增功能&#xff1a; 视频编码和转换&#xff1a;支持将各种视频格式进…

代码随想录算法训练营第四十三天丨 动态规划part06

518.零钱兑换II 思路 这是一道典型的背包问题&#xff0c;一看到钱币数量不限&#xff0c;就知道这是一个完全背包。 对完全背包还不了解的同学&#xff0c;可以看这篇&#xff1a;动态规划&#xff1a;关于完全背包&#xff0c;你该了解这些&#xff01;(opens new window)…