RRT算法学习及MATLAB演示

news2024/11/18 23:35:09

文章目录

  • 1 前言
  • 2 算法简介
  • 3 MATLAB实现
    • 3.1 定义地图
    • 3.2 绘制地图
    • 3.3 定义参数
    • 3.4 绘制起点和终点
    • 3.5 RRT算法
      • 3.5.1 代码
      • 3.5.2 效果
      • 3.5.3 代码解读
  • 4 参考
  • 5 完整代码

1 前言

RRT(Rapid Random Tree)算法,即快速随机树算法,是LaValle在1998年首次提出的一种高效的路径规划算法。RRT算法以初始的一个根节点,通过随机采样的方法在空间搜索,然后添加一个又一个的叶节点来不断扩展随机树。当目标点进入随机树里面后,随机树扩展立即停止,此时能找到一条从起始点到目标点的路径。

两个代码文件见最后一节。

2 算法简介

效果预览图
在这里插入图片描述
算法的计算过程如下:
step1:初始化随机树。将环境中起点作为随机树搜索的起点,此时树中只包含一个节点即根节点;
stpe2:在环境中随机采样。在环境中随机产生一个点,若该点不在障碍物范围内则计算随机树中所有节点到的欧式距离,并找到距离最近的节点,若在障碍物范围内则重新生成并重复该过程直至找到;
stpe3:生成新节点。在和连线方向,由指向固定生长距离生成一个新的节点,并判断该节点是否在障碍物范围内,若不在障碍物范围内则将添加到随机树 中,否则的话返回step2重新对环境进行随机采样;
step4:停止搜索。当和目标点之间的距离小于设定的阈值时,则代表随机树已经到达了目标点,将作为最后一个路径节点加入到随机树中,算法结束并得到所规划的路径 。

3 MATLAB实现

3.1 定义地图

地图是模拟的栅格地图,resolution表示每个格子的长度,这里设置为1,地图范围为 x ∈ [ − 15 , 15 ] x\in[-15,15] x[15,15], y ∈ [ − 15 , 15 ] y\in[-15,15] y[15,15]。障碍物的形状为矩形,定义方式为矩形的左下角坐标及其水平长度和竖直长度。wall_obstacle位于地图边界,block_obstacle位于地图内部。

%% Define the map
resolution = 1; % resolution, cell length

% Map boundaries
left_bound = -15;
right_bound = 15;
lower_bound = -15;
upper_bound = 15;

% Wall obstacle [left_down_x,left_down_y,horizontal_length,vertical_length]
wall_obstacle(1,:) = [   left_bound,   lower_bound,                        1, upper_bound-lower_bound-1]; % left boundary
wall_obstacle(2,:) = [ left_bound+1,   lower_bound, right_bound-left_bound-1,                         1]; % bottom boundary
wall_obstacle(3,:) = [right_bound-1, lower_bound+1,                        1, upper_bound-lower_bound-1]; % right boundary
wall_obstacle(4,:) = [   left_bound, upper_bound-1, right_bound-left_bound-1,                         1]; % up boundary

% Blcok obstacle [left_down_x,left_down_y,horizontal_length,vertical_length]
block_obstacle(1,:) = [0,-10,10,5]; % block obstacle 1
block_obstacle(2,:) = [-5,5,5,9]; % block obstacle 2
block_obstacle(3,:) = [-5,-2,5,4]; % block obstacle 3

ob = [block_obstacle; wall_obstacle];

3.2 绘制地图

%% Draw the map
figure(1); % create a figure

% Figure setting
set(gca,'XLim',[left_bound right_bound]); % x axis range
set(gca,'XTick',[left_bound:resolution:right_bound]); % x axis tick
set(gca,'YLim',[lower_bound upper_bound]); % y axis range
set(gca,'YTick',[lower_bound:resolution:upper_bound]); % y axis tick
grid on
axis equal
title('RRT');
xlabel('x');
ylabel('y');

hold on

% Draw the obstacles
for i=1:1:size(ob,1)
    fill([ob(i,1),ob(i,1)+ob(i,3),ob(i,1)+ob(i,3),ob(i,1)],...
         [ob(i,2),ob(i,2),ob(i,2)+ob(i,4),ob(i,2)+ob(i,4)],'k');
end

结果如下图所示,这里用红框标出了wall_obstacle,用绿色数字表示block_obstacle。
在这里插入图片描述

3.3 定义参数

grow_distance指新生长出的节点与其父节点的距离,这里设为1;goal_distance指的是如果新生长出的节点落在这个范围里,则认为已经到达终点;goal的位置设为 [ − 10 , − 10 ] [-10,-10] [10,10],start的位置设为 [ 13 , 10 ] [13,10] [13,10]

%% Initialize parameters
grow_distance = 1; % distance between parent node and the derived child node
goal_radius = 1.5; % can be considered as reaching the goal once within this range
% Goal point position
goal.x = -10;
goal.y = -10;
% Start point position
start.x = 13;
start.y = 10;

3.4 绘制起点和终点

%% Draw the start point and the end point
h_start = plot(start.x,start.y,'b^','MarkerFaceColor','b','MarkerSize',5*resolution);
h_goal = plot(goal.x,goal.y,'m^','MarkerFaceColor','m','MarkerSize',5*resolution);

% Draw the goal circle
theta = linspace(0,2*pi);
goal_circle.x = goal_radius*cos(theta) + goal.x;
goal_circle.y = goal_radius*sin(theta) + goal.y;
plot(goal_circle.x,goal_circle.y,'--k','LineWidth',0.8*resolution);

在这里插入图片描述

3.5 RRT算法

这一部分主要是用于演示RRT算法是怎么建树,怎么到达给定终点,侧重于展示RRT的思想,如果用于工程实现,则需要用C++等高级语言重写,并且使用严谨的数据结构。

3.5.1 代码

注意需要另外写一个函数find_closet_node.m

function [angle,min_idx] = find_closet_node(rd_x,rd_y,tree)
    distance = [];
    i = 1;
    while i <= length(tree.child) % should not use size() function
        dx = rd_x - tree.child(i).x;
        dy = rd_y - tree.child(i).y;
        distance(i) = sqrt(dx^2 + dy^2);
        i = i+1;
    end
    [~,min_idx] = min(distance);
    angle = atan2(rd_y-tree.child(min_idx).y, rd_x-tree.child(min_idx).x);
end

下面的代码承接3.4节即可

%% RRT Algorithm
% Initialize the random tree(in the form of struct)
tree.child = []; % current node
tree.parent = []; % current node's parent
tree.distance = []; % current node's distance to the start

tree.child = start;
tree.parent = start;
tree.distance = 0;

new_node.x = start.x;
new_node.y = start.y;

goal_distance = sqrt((goal.x - new_node.x)^2 + (goal.y - new_node.y)^2);

% Main loop
while goal_distance > goal_radius
    random_point.x = (right_bound - left_bound) * rand() + left_bound; % random x value between x limit
    random_point.y = (upper_bound - lower_bound) * rand() + lower_bound; % random y value between y limit
    handle_1 = plot(random_point.x,random_point.y,'p','MarkerEdgeColor',[0.9290 0.6940 0.1250],'MarkerFaceColor',[0.9290 0.6940 0.1250],'MarkerSize',8*resolution); % draw the randomly generated point
    [angle,min_idx] = find_closet_node(random_point.x,random_point.y,tree);
    
    % pause(0.5)
    handle_2 = plot([tree.child(min_idx).x,random_point.x],[tree.child(min_idx).y,random_point.y],'-','Color',[0.7 0.7 0.7],'LineWidth',0.8*resolution); % draw the segment between the closest tree node and the randomly generated point
    
    % pause(0.5)
    new_node.x = tree.child(min_idx).x + grow_distance*cos(angle);
    new_node.y = tree.child(min_idx).y + grow_distance*sin(angle);
    handle_3 = plot(new_node.x,new_node.y,'.r','MarkerFaceColor','r','MarkerSize',10*resolution); % draw the potential new node
    
    flag = 1; % default: valid node

    % Judge if the new node is inside the obstacle
    step = 0.01;
    if new_node.x < tree.child(min_idx).x
        step = -step;
    end
    for k=1:1:size(ob,1)
        for i=tree.child(min_idx).x:step:new_node.x
            if angle>pi/2-5e-02 && angle<pi/2+5e-02
                j = tree.child(min_idx).y+1;
            elseif angle>-pi/2-5e-02 && angle<-pi/2+5e-02
                j = tree.child(min_idx).y-1;
            else
                j=tree.child(min_idx).y+(i-tree.child(min_idx).x)*tan(angle);
            end
            if i>=ob(k,1) && i<=(ob(k,1)+ob(k,3))
                if j >=ob(k,2) && j<=ob(k,2)+ob(k,4)
                    flag = 0; % invalid node
                    break
                end
            end
        end
        if flag==0
            break
        end
    end

    % pause(0.5)
    if flag==1
        tree.child(end+1) = new_node;
        tree.parent(end+1) = tree.child(min_idx);
        tree.distance(end+1) = 1 + tree.distance(min_idx);
        goal_distance = sqrt((goal.x - new_node.x)^2 + (goal.y - new_node.y)^2);
        delete(handle_3)
        plot(new_node.x,new_node.y,'.g','MarkerFaceColor','g','MarkerSize',10*resolution); % draw the new node
        % pause(0.2)
        plot([tree.child(min_idx).x,new_node.x],[tree.child(min_idx).y,new_node.y],'-k','LineWidth',0.8*resolution); % draw the segment between the closest tree node and the new node
    end
    
    % pause(0.5)
    delete(handle_1);
    delete(handle_2);
    % pause(0.5)
end

3.5.2 效果

在这里插入图片描述

3.5.3 代码解读

  • 首先是初始化一个tree结构体,含有child, parent, distance三个成员,三者均为列表。child用于存储所有节点,在相同索引位置,parent存储child的父节点,distance存储child到起点的距离(沿着树的距离,不是直线距离)。然后对这三个成员进行初始化。

    % Initialize the random tree(in the form of struct)
    tree.child = []; % current node
    tree.parent = []; % current node's parent
    tree.distance = []; % current node's distance to the start
    
    tree.child = start;
    tree.parent = start;
    tree.distance = 0;
    
  • 定义全局变量,new_node,用于存储新衍生出来的节点,用起点对其初始化。
    定义全局变量,goal_distance,用于存储new_node到终点的距离。

    new_node.x = start.x;
    new_node.y = start.y;
    
    goal_distance = sqrt((goal.x - new_node.x)^2 + (goal.y - new_node.y)^2);
    
  • 进入主循环,只要new_node尚未到达终点范围,则循环继续。

    • 每个循环中,在地图范围内生成一个随机点,然后找到距离该随机点最近的树上的节点(借助自定义函数find_closet_node实现),返回该点的索引,以及这两点连线的角度。【生成的随机点用黄色五角星表示】【随机点与最近的树上节点的连线用灰色表示】

      random_point.x = (right_bound - left_bound) * rand() + left_bound; % random x value between x limit
      random_point.y = (upper_bound - lower_bound) * rand() + lower_bound; % random y value between y limit
      handle_1 = plot(random_point.x,random_point.y,'p','MarkerEdgeColor',[0.9290 0.6940 0.1250],'MarkerFaceColor',[0.9290 0.6940 0.1250],'MarkerSize',8*resolution); % draw the randomly generated point
      [angle,min_idx] = find_closet_node(random_point.x,random_point.y,tree);
      
      % pause(0.5)
      handle_2 = plot([tree.child(min_idx).x,random_point.x],		[tree.child(min_idx).y,random_point.y],'-','Color',[0.7 0.7 0.7],'LineWidth',0.8*resolution); % draw the segment between the closest tree node and the randomly generated point
      
      
      function [angle,min_idx] = find_closet_node(rd_x,rd_y,tree)
          distance = [];
          i = 1;
          while i <= length(tree.child) % should not use size() function
              dx = rd_x - tree.child(i).x;
              dy = rd_y - tree.child(i).y;
              distance(i) = sqrt(dx^2 + dy^2);
              i = i+1;
          end
          [~,min_idx] = min(distance);
          angle = atan2(rd_y-tree.child(min_idx).y, rd_x-tree.child(min_idx).x);
      end
      
    • 在这两点连线上,生成一个新节点,新节点与树上的节点距离为1,默认该节点是有效的,也即不会与障碍物干涉的。【新节点用红色实心点表示】

      	% pause(0.5)
          new_node.x = tree.child(min_idx).x + grow_distance*cos(angle);
          new_node.y = tree.child(min_idx).y + grow_distance*sin(angle);
          handle_3 = plot(new_node.x,new_node.y,'.r','MarkerFaceColor','r','MarkerSize',10*resolution); % draw the potential new node
          
          flag = 1; % default: valid node
      
    • 然后判断生成的新节点与树上节点的连线上的点是否位于障碍物内,也即判断新节点是否会导致路径与障碍物干涉,如果发生干涉,则把flag设置为0。

      % Judge if the new node is inside the obstacle
      step = 0.01;
      if new_node.x < tree.child(min_idx).x
          step = -step;
      end
      for k=1:1:size(ob,1)
          for i=tree.child(min_idx).x:step:new_node.x
              if angle>pi/2-5e-02 && angle<pi/2+5e-02
                  j = tree.child(min_idx).y+1;
              elseif angle>-pi/2-5e-02 && angle<-pi/2+5e-02
                  j = tree.child(min_idx).y-1;
              else
                  j=tree.child(min_idx).y+(i-tree.child(min_idx).x)*tan(angle);
              end
              if i>=ob(k,1) && i<=(ob(k,1)+ob(k,3))
                  if j >=ob(k,2) && j<=ob(k,2)+ob(k,4)
                      flag = 0; % invalid node
                      break
                  end
              end
          end
          if flag==0
              break
          end
      end
      
    • 如果没有发生干涉,则将该点加入child列表,并将上一个点加入parent列表,该点距离起点的距离等于grow_distance加上上一个点距离起点的距离。【如果新节点在可行区域,则将该节点画为绿色】【该可行新节点与上一个节点的连线为黑色】【擦除之前生成的五角星随机点】【擦除之前五角星随机点与树上节点的连线】

      % pause(0.5)
      if flag==1
      	 tree.child(end+1) = new_node;
      	 tree.parent(end+1) = tree.child(min_idx);
      	 tree.distance(end+1) = grow_distance + tree.distance(min_idx);
      	 goal_distance = sqrt((goal.x - new_node.x)^2 + (goal.y - new_node.y)^2);
      	 delete(handle_3)
      	 plot(new_node.x,new_node.y,'.g','MarkerFaceColor','g','MarkerSize',10*resolution); % draw the new node
      	 % pause(0.2)
      	 plot([tree.child(min_idx).x,new_node.x],[tree.child(min_idx).y,new_node.y],'-k','LineWidth',0.8*resolution); % draw the segment between the closest tree node and the new node
      end
      
      % pause(0.5)
      delete(handle_1);
      delete(handle_2);
      % pause(0.5)
      

4 参考

RRT, RRT* & Random Trees
全局路径规划 - RRT算法原理及实现

5 完整代码

将下面两个文件放在同一文件夹下,运行(或分节运行)RRT_learn.m即可。此外,需要动态观察算法效果则把所有pause语句取消注释。
find_closest_node.m

function [angle,min_idx] = find_closest_node(rd_x,rd_y,tree)
    distance = [];
    i = 1;
    while i <= length(tree.child) % should not use size() function
        dx = rd_x - tree.child(i).x;
        dy = rd_y - tree.child(i).y;
        distance(i) = sqrt(dx^2 + dy^2);
        i = i+1;
    end
    [~,min_idx] = min(distance);
    angle = atan2(rd_y-tree.child(min_idx).y, rd_x-tree.child(min_idx).x);
end

RRT_learn.m

%%
clear all
clc
%% Notification
% 1,用户自定义的内容:地图范围,障碍物数量和大小,起点和终点的位置,终点范围的阈值,RRT树生长一次的长度,和绘图相关的设置
% 2,需要演示算法效果的时候,把所有pause取消注释;不需要演示算法效果的时候,把所有pause加上注释
%% Define the map
resolution = 1; % resolution, cell length

left_bound = -15;
right_bound = 15;
lower_bound = -15;
upper_bound = 15;

% Wall obstacle [left_down_x,left_down_y,horizontal_length,vertical_length]
wall_obstacle(1,:) = [   left_bound,   lower_bound,                        1, upper_bound-lower_bound-1]; % left boundary
wall_obstacle(2,:) = [ left_bound+1,   lower_bound, right_bound-left_bound-1,                         1]; % bottom boundary
wall_obstacle(3,:) = [right_bound-1, lower_bound+1,                        1, upper_bound-lower_bound-1]; % right boundary
wall_obstacle(4,:) = [   left_bound, upper_bound-1, right_bound-left_bound-1,                         1]; % up boundary

% Blcok obstacle [left_down_x,left_down_y,horizontal_length,vertical_length]
block_obstacle(1,:) = [0,-10,10,5]; % block obstacle 1
block_obstacle(2,:) = [-5,5,5,9]; % block obstacle 2
block_obstacle(3,:) = [-5,-2,5,4]; % block obstacle 3

ob = [block_obstacle; wall_obstacle];
%% Draw the map
figure(1); % create a figure

% Figure setting
set(gca,'XLim',[left_bound right_bound]); % x axis range
set(gca,'XTick',[left_bound:resolution:right_bound]); % x axis tick
set(gca,'YLim',[lower_bound upper_bound]); % y axis range
set(gca,'YTick',[lower_bound:resolution:upper_bound]); % y axis tick
grid on
axis equal
title('RRT');
xlabel('x');
ylabel('y');

hold on

% Draw the obstacles
for i=1:1:size(ob,1)
    fill([ob(i,1),ob(i,1)+ob(i,3),ob(i,1)+ob(i,3),ob(i,1)],...
         [ob(i,2),ob(i,2),ob(i,2)+ob(i,4),ob(i,2)+ob(i,4)],'k');
end

%% Initialize parameters
grow_distance = 1; % distance between parent node and the derived child node
goal_radius = 1.5; % can be considered as reaching the goal once within this range
% Goal point position
goal.x = -10;
goal.y = -10;
% Start point position
start.x = 13;
start.y = 10;
%% Draw the start point and the end point
h_start = plot(start.x,start.y,'b^','MarkerFaceColor','b','MarkerSize',5*resolution);
h_goal = plot(goal.x,goal.y,'m^','MarkerFaceColor','m','MarkerSize',5*resolution);

% Draw the goal circle
theta = linspace(0,2*pi);
goal_circle.x = goal_radius*cos(theta) + goal.x;
goal_circle.y = goal_radius*sin(theta) + goal.y;
plot(goal_circle.x,goal_circle.y,'--k','LineWidth',0.8*resolution);
%% RRT Algorithm
% Initialize the random tree(in the form of struct)
tree.child = []; % current node
tree.parent = []; % current node's parent
tree.distance = []; % current node's distance to the start

tree.child = start;
tree.parent = start;
tree.distance = 0;

new_node.x = start.x;
new_node.y = start.y;

goal_distance = sqrt((goal.x - new_node.x)^2 + (goal.y - new_node.y)^2);

% Main loop
while goal_distance > goal_radius
    random_point.x = (right_bound - left_bound) * rand() + left_bound; % random x value between x limit
    random_point.y = (upper_bound - lower_bound) * rand() + lower_bound; % random y value between y limit
    handle_1 = plot(random_point.x,random_point.y,'p','MarkerEdgeColor',[0.9290 0.6940 0.1250],'MarkerFaceColor',[0.9290 0.6940 0.1250],'MarkerSize',8*resolution); % draw the randomly generated point
    [angle,min_idx] = find_closest_node(random_point.x,random_point.y,tree);
    
    % pause(0.5)
    handle_2 = plot([tree.child(min_idx).x,random_point.x],[tree.child(min_idx).y,random_point.y],'-','Color',[0.7 0.7 0.7],'LineWidth',0.8*resolution); % draw the segment between the closest tree node and the randomly generated point
    
    % pause(0.5)
    new_node.x = tree.child(min_idx).x + grow_distance*cos(angle);
    new_node.y = tree.child(min_idx).y + grow_distance*sin(angle);
    handle_3 = plot(new_node.x,new_node.y,'.r','MarkerFaceColor','r','MarkerSize',10*resolution); % draw the potential new node
    
    flag = 1; % default: valid node

    % Judge if the new node is inside the obstacle
    step = 0.01;
    if new_node.x < tree.child(min_idx).x
        step = -step;
    end
    for k=1:1:size(ob,1)
        for i=tree.child(min_idx).x:step:new_node.x
            if angle>pi/2-5e-02 && angle<pi/2+5e-02
                j = tree.child(min_idx).y+1;
            elseif angle>-pi/2-5e-02 && angle<-pi/2+5e-02
                j = tree.child(min_idx).y-1;
            else
                j=tree.child(min_idx).y+(i-tree.child(min_idx).x)*tan(angle);
            end
            if i>=ob(k,1) && i<=(ob(k,1)+ob(k,3))
                if j >=ob(k,2) && j<=ob(k,2)+ob(k,4)
                    flag = 0; % invalid node
                    break
                end
            end
        end
        if flag==0
            break
        end
    end

    % pause(0.5)
    if flag==1
        tree.child(end+1) = new_node;
        tree.parent(end+1) = tree.child(min_idx);
        tree.distance(end+1) = 1 + tree.distance(min_idx);
        goal_distance = sqrt((goal.x - new_node.x)^2 + (goal.y - new_node.y)^2);
        delete(handle_3)
        plot(new_node.x,new_node.y,'.g','MarkerFaceColor','g','MarkerSize',10*resolution); % draw the new node
        % pause(0.2)
        plot([tree.child(min_idx).x,new_node.x],[tree.child(min_idx).y,new_node.y],'-k','LineWidth',0.8*resolution); % draw the segment between the closest tree node and the new node
    end
    
    % pause(0.5)
    delete(handle_1);
    delete(handle_2);
    % pause(0.5)
end

%% Draw the final path
final_distance = tree.distance(end);
title('RRT, distance:',num2str(final_distance));

current_index = length(tree.child);
while current_index ~= 1
    plot([tree.child(current_index).x,tree.parent(current_index).x],[tree.child(current_index).y,tree.parent(current_index).y],'-','LineWidth',1.5*resolution,'Color',[0.8500 0.3250 0.0980]); % draw the segment between the closest tree node and the new node    
    for i=1:length(tree.child)
        if tree.child(i).x == tree.parent(current_index).x
            if tree.child(i).y == tree.parent(current_index).y
                current_index = i;
                break
            end
        end
    end
end

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

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

相关文章

C语言第三十二弹---自定义类型:联合和枚举

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 目录 1、联合体 1.1、联合体类型的声明 1.2、联合体的特点 1.3、相同成员的结构体和联合体对比 1.4、联合体大小的计算 1.5、联合的⼀个练习 2、枚举类型 …

176基于matlab的自适应滤波法预测

基于matlab的自适应滤波法预测&#xff0c;自适应滤波预测实质上是一种加权滑动平均预测&#xff0c;通过迭代得到最佳权值&#xff0c;并给出了相对误差图和预测效果图&#xff0c;程序已调通&#xff0c;可直接运行。 176matlab自适应滤波法预测 时间序列预测 (xiaohongshu.c…

51单片机(6)-----直流电机的介绍与使用(通过独立按键控制电机的运行)

前言&#xff1a;感谢您的关注哦&#xff0c;我会持续更新编程相关知识&#xff0c;愿您在这里有所收获。如果有任何问题&#xff0c;欢迎沟通交流&#xff01;期待与您在学习编程的道路上共同进步。 目录 一. 直流电机模块介绍 1.直流电机介绍 2.电机参数 二. 程序设计…

java线程池原理源码解析,程序员如何技术划水

前言 面试大概九十分钟&#xff0c;问的东西很全面&#xff0c;需要做充足准备&#xff0c;就是除了概念以外问的有点懵逼了。回来之后把这些题目做了一个分类并整理出答案&#xff08;强迫症的我~狂补知识&#xff09;分为MySQLJavaRedis算法网络Linux等六类&#xff0c;接下…

2024-02-28(Kafka,Oozie,Flink)

1.Kafka的数据存储形式 一个主题由多个分区组成 一个分区由多个segment段组成 一个segment段由多个文件组成&#xff08;log&#xff0c;index&#xff08;稀疏索引&#xff09;&#xff0c;timeindex&#xff08;根据时间做的索引&#xff09;&#xff09; 2.读数据的流程 …

Swagger接口文档管理工具

Swagger 1、Swagger1.1 swagger介绍1.2 项目集成swagger流程1.3 项目集成swagger 2、knife4j2.1 knife4j介绍2.2 项目集成knife4j 1、Swagger 1.1 swagger介绍 官网&#xff1a;https://swagger.io/ Swagger 是一个规范和完整的Web API框架&#xff0c;用于生成、描述、调用和…

textbox跨线程写入

实现实例1 实现效果 跨线程实现 // 委托&#xff0c;用于定义在UI线程上执行的方法签名 //public delegate void SetTextCallback(string text);public void textBoxText(string text){// 检查调用线程是否是创建控件的线程 if (textBox1.InvokeRequired){// 如果不是&#…

React UI框架Antd 以及 如何按需引入css样式配置(以及过程中各种错误处理方案)

一、react UI框架Antd使用 1.下载模块 npm install antd -S 2.引入antd的样式 import ../node_modules/antd/dist/reset.css; 3.局部使用antd组件 import {Button, Calendar} from antd; import {PieChartTwoTone} from ant-design/icons; {/* 组件汉化配置 */} import l…

Ant for Blazor做单个表的增删查改

Ant for Blazor做单个表的增删查改 2024年02月27日花了一天时间弄出来了&#xff0c;基本弄好了&#xff0c;vs2022blazor servernet8,引用的AntDesign版本是0.17.4 代码里的model和repository是用自己牛腩代码生成器生成的东西&#xff0c;sqlsugar的&#xff0c;记得在prog…

ROS 2基础概念#1:计算图(Compute Graph)| ROS 2学习笔记

在ROS中&#xff0c;计算图&#xff08;ROS Compute Graph&#xff09;是一个核心概念&#xff0c;它描述了ROS节点之间的数据流动和通信方式。它不仅仅是一个通信网络&#xff0c;它也反映了ROS设计哲学的核心——灵活性、模块化和可重用性。通过细致探讨计算图的高级特性和实…

面试数据库篇(mysql)- 12分库分表

拆分策略 垂直分库 垂直分库:以表为依据,根据业务将不同表拆分到不同库中。 特点: 按业务对数据分级管理、维护、监控、扩展在高并发下,提高磁盘IO和数据量连接数垂直分表:以字段为依据,根据字段属性将不同字段拆分到不同表中。 特点: 1,冷热数据分离 2,减少IO过渡争…

CSS——PostCSS简介

文章目录 PostCSS是什么postCSS的优点补充&#xff1a;polyfill补充&#xff1a;Stylelint PostCSS架构概述工作流程PostCSS解析方法PostCSS解析流程 PostCSS插件插件的使用控制类插件包类插件未来的CSS语法相关插件后备措施相关插件语言扩展相关插件颜色相关组件图片和字体相关…

Rocky Linux安装部署Elasticsearch(ELK日志服务器)

一、Elasticsearch的简介 Elasticsearch是一个强大的开源搜索和分析引擎&#xff0c;可用于实时处理和查询大量数据。它具有高性能、可扩展性和分布式特性&#xff0c;支持全文搜索、聚合分析、地理空间搜索等功能&#xff0c;是构建实时应用和大规模数据分析平台的首选工具。 …

车牌识别-只用opencv的方式

项目简述 本文描述如何只使用opencv将车牌中的车牌号提取出来&#xff0c;整个过程大致分为三个过程&#xff1a;车牌定位&#xff0c;车牌号元素分割&#xff0c;模式匹配。 在做完这个实验后&#xff0c;我感触是&#xff0c;只用opencv的方式能使用的场景有限&#xff0c;不…

2.27数据结构

1.链队 //link_que.c #include "link_que.h"//创建链队 Q_p create_que() {Q_p q (Q_p)malloc(sizeof(Q));if(qNULL){printf("空间申请失败\n");return NULL;}node_p L(node_p)malloc(sizeof(node));if(LNULL){printf("申请空间失败\n");return…

【八股文学习日记】集合概述

【八股文学习日记】集合概述 集合概述 Java 集合&#xff0c; 也叫作容器&#xff0c;主要是由两大接口派生而来&#xff1a;一个是 Collection接口&#xff0c;主要用于存放单一元素&#xff1b;另一个是 Map 接口&#xff0c;主要用于存放键值对。对于Collection 接口&#…

深入理解分库、分表、分库分表

前言 分库分表&#xff0c;是企业里面比较常见的针对高并发、数据量大的场景下的一种技术优化方案&#xff0c;所谓"分库分表"&#xff0c;根本就不是一件事儿&#xff0c;而是三件事儿&#xff0c;他们要解决的问题也都不一样&#xff0c;这三个事儿分别是"只…

kali安装ARL灯塔(docker)

1、root身份进入容器 ┌──(root㉿Kali)-[~/桌面] └─# su root ┌──(root㉿Kali)-[~/桌面] └─# docker 2、先更新再克隆 ┌──(root㉿Kali)-[~/桌面] └─# apt-get update …

【Android安全】Windows 环境下载 AOSP 源码

准备环境 安装 git 安装 Python 硬盘剩余容量最好大于 800G 打开 Git Bash&#xff0c;用 git 克隆源代码仓库 git clone https://android.googlesource.com/platform/manifest.git //没有梯子使用清华源 git clone https://aosp.tuna.tsinghua.edu.cn/platform/manifest.git这…

mac苹果电脑系统最好用的清理软件CleanMyMac2024功能介绍及如何激活解锁许可证

CleanMyMac X的界面设计简洁大气&#xff0c;为用户提供了直观且易于操作的使用体验。 布局清晰&#xff1a;界面布局非常明朗&#xff0c;左侧是功能栏&#xff0c;右侧则是信息界面。这种布局方式使得用户能够迅速找到所需的功能选项&#xff0c;提高了操作效率。色彩搭配&a…