石磊 发表于 2024-7-15 18:49

学习笔记:A*算法matlab实现

A*算法是一种很常用很经典的路径搜索算法。与Dijkstra算法对比,Dijkstra算法计算一个点到其他点的最短路径,而A*算法存眷点到点的最短路径。Dijkstra算法的广度优先算法,A*算法是启发式算法,类似于深度优先算法。关于A*算法其他介绍本文不再赘述,重点存眷A*算法的伪代码和matlab实现。
A*算法伪代码:
* 初始化open_set和close_set;
* 将起点插手open_set中,并设置cost为0(优先级最高);
* 如果open_set不为空,则从open_set中拔取cost最小的节点n:
    * 如果节点n为终点,则:
      * 从终点开始逐步追踪parent节点,一直达到起点;
      * 返回找到的成果路径,算法结束;
    * 如果节点n不是终点,则:
      * 将节点n从open_set中删除,并插手close_set中;
      * 遍历节点n所有的邻近节点:
            * 如果邻近节点m在close_set中,则:
                * 跳过,拔取下一个邻近节点
            * 如果邻近节点m也不在open_set中,则:
                * 设置节点m的parent为节点n
                * 计算节点m的cost
                * 将节点m插手open_set中
            * 如果邻近节点m在open_set中,则:
                * 若节点m的cost小于本来的cost:
                  * 更新节点m的cost
                  * 设置节点m的parent为节点nA*算法matlab实现:
function = AStar(map, p_start, p_goal)
    [~, mapWidth] = size(map);
    p_start_index = getIndex(p_start, mapWidth);
    p_goal_index = getIndex(p_goal, mapWidth);
    openList = ; % 为了拔取cost最小的节点,open_set中也存放了节点的代价
    closeList = [];
    % costTable存放了节点id、到起点的欧式距离、到终点的曼哈顿距离、节点的估计代价
    costTable = ;
    edges = int32.empty(0, 2);
    while ~isempty(openList)
      [~, min_cost_index] = min(openList(2, :));
      p_current_index = openList(1, min_cost_index); % 拔取cost最小的节点作为当前节点
      openList(:, min_cost_index) = [];
      closeList = ;
      p_current = index2node(p_current_index, mapWidth);
      if (isequal(p_current, p_goal)) % 如果当前节点就是终点,回溯得到起点到终点之间的路径
            path = findPath(edges, p_start_index, p_goal_index, mapWidth);
            return;
      end
      % 遍历当前节点的邻居节点
      for i = -1 : 1
            for j = -1 : 1
                p_neig = p_current + int32();
                p_neig_index = getIndex(p_neig, mapWidth);
                % 如果邻居节点不成行或者已经在close_set中,跳过
                if ~isNodeFree(map, p_neig) || ~isempty(find(closeList == p_neig_index, 1))
                  continue;
                end
                % 计算邻居节点的估计代价
                = cost(p_neig, p_current, p_current_index, costTable, p_goal);
                if isempty(find(openList(1, :) == p_neig_index, 1))
                  openList = ];
                  costTable = ];
                  edges = ];
                else
                  [~, column] = find(costTable(1, :) == p_neig_index);
                  if costOfPNeig < costTable(4, column)
                        % 若邻居节点已经在open_set中且新cost小于原cost,则更新邻居节点的估计代价和父节点
                         = find(edges(:, 1) == p_neig_index);
                        edges(row, :) = [];
                        edges = ];
                        costTable(:, column) = [];
                        costTable = ];
                        [~, col] = find(openList(1, :) == p_neig_index);
                        openList(:, col) = [];
                        openList = ];
                  end
                end
            end
      end
    end
end以上就是A*算法的matlab实现,下面对此中的一些自定义函数进行补充:
% 获取节点在地图中的id
function = getIndex(p, mapWidth)
    index = p(2) + mapWidth * (p(1) - 1);
    index = int32(index);
end

% 将节点id转换成节点坐标
function coordinate = index2node(index, mapWidth)
    y = int32(mod(index, mapWidth));
    if y == 0
      y = mapWidth;
    end
    x = int32((index-y)/mapWidth + 1);
    coordinate = int32();
end

% 计算两个节点之间的欧式距离
function = Edistance(p1, p2)
    p1_p2 = int32(p1) - int32(p2);
    if p1_p2(1) == 0 && p1_p2(2) == 0
      Ed = 0;
    elseif p1_p2(1) == 0 || p1_p2(2) == 0
      Ed = 10;
    else
      Ed = 14;
    end
    Ed = int32(Ed);
end

% 计算两个节点之间的曼哈顿距离
function = Mdistance(p1,p2)
    p1_p2 = int32(p1) - int32(p2);
    Md = abs(p1_p2(1)) + abs(p1_p2(2));
    Md = Md * 10;
    Md = int32(Md);
end

% 判断节点是否为可行节点
function = isNodeFree(map, p)
    = size(map);
    if p(1) < 1 || p(2) < 1 || p(1) > mapLength || p(2) > mapWidth
      isFree = 0;
    else
      isFree = ~map(p(1), p(2));
    end
end

% 计算邻居节点到起点的欧式距离、到终点的曼哈顿距离、节点的估计代价
function = cost(p_neig, p_current, p_current_index, costTable, p_goal)
    [~, column] = find(costTable(1, :) == p_current_index);
    di2start = int32(costTable(2, column)) + Edistance(p_neig, p_current);
    Md2goal = Mdistance(p_neig, p_goal);
    co = int32(di2start + Md2goal);
end

% 通过回溯得到该算法实现找到的最优路径
function = findPath(edges, p_start_index, p_goal_index, mapWidth)
    = find(edges(:, 1) == p_goal_index);
    index_son = edges(row, 1);
    index_father = edges(row, 2);
    path = index2node(index_son, mapWidth);
    while index_father ~= p_start_index
       = find(edges(:, 1) == index_father);
      index_son = index_father;
      path = ;
      index_father = edges(row, 2);
    end
    path = ;
    path = flipud(path);
end至此,我们完成了A*算法的matlab实现。通过读取png图像作为二维地图,并对障碍物进行膨胀操作,执行A*算法得到如下的效果:


通过上图可以看出,A*算法能够搜索出一条可行路径,但是存在一些问题,例如:

[*]存在多余的拐点;
[*]搜索出来的路径不够平滑;
[*]没有考虑实际的运动学约束。
针对这些问题,可以通过去除多余拐点,曲线插值/拟合,考虑机器人实际的运动学模型等方式来解决。


上图为针对上述问题进行优化后的最终效果,可以看到优化后的路径对比于原始路径有不少的提升,但仍存在可以改良的处所,后续将运用更多方式针对路径优化进行探究。
页: [1]
查看完整版本: 学习笔记:A*算法matlab实现