matlab三维A*算法 Astar三维路径规划 超详细注释 可自定义地图 自定义障碍物栅格数量和颜色 路径颜色 修改代价函数 预设5种常见评价指标 可

最近在搞无人机路径规划,发现三维A*算法真是个好东西。不过网上现成的代码要么注释太少,要么扩展性差,干脆自己撸了个带超详细注释的版本。先看效果:输入起点终点,唰一下生成带评价指标的路径,障碍物颜色和密度都能调,连路径颜色都能自定义。老规矩,先上效果图(假装有图),咱们直接看代码怎么玩转三维空间。

先看节点结构体定义,这里藏着算法的核心逻辑:

classdef Node
    properties
        x           % 三维坐标
        y
        z
        parent      % 父节点
        g_cost      % 实际代价
        h_cost      % 启发代价
        f_cost      % 总代价
        is_obstacle % 障碍标记
    end
    methods
        function obj = Node(x, y, z)
            obj.x = x;
            obj.y = y;
            obj.z = z;
        end
    end
end

这里把每个三维坐标点封装成对象,parent属性用来回溯路径。gcost是起点到当前点的实际代价,hcost是到终点的预估代价,这俩加起来就是总代价fcost。想改代价计算方式?直接去改fcost的计算逻辑就行。

接着是代价计算函数,这里预设了三种常见启发函数:

function h = heuristic(node, goal, type)
    dx = abs(node.x - goal.x);
    dy = abs(node.y - goal.y);
    dz = abs(node.z - goal.z);
    
    switch type
        case 'manhattan'
            h = dx + dy + dz;
        case 'euclidean'
            h = sqrt(dx^2 + dy^2 + dz^2);
        case 'diagonal'
            [~, idx] = sort([dx, dy, dz]);
            h = dz*(sqrt(3)-sqrt(2)) + dy*(sqrt(2)-1) + dx;
        otherwise
            error('不支持的启发函数类型');
    end
end

想换启发方式?改第三个参数就行。比如把'euclidean'换成'diagonal',立马切换对角线距离计算方式。

障碍物生成部分更有意思,可以玩出不同花样:

function map = generate_obstacles(map, obstacle_density, color)
    % 随机生成球形障碍物
    num_obstacles = round(obstacle_density * numel(map));
    for i = 1:num_obstacles
        [x,y,z] = ind2sub(size(map), randi(numel(map)));
        radius = randi([1,3]);  % 障碍物半径
        % 球形膨胀算法
        [X,Y,Z] = meshgrid(1:size(map,1),1:size(map,2),1:size(map,3));
        dist = sqrt((X-x).^2 + (Y-y).^2 + (Z-z).^2);
        map(dist <= radius) = struct('is_obstacle', true, 'color', color);
    end
end

这里用球形膨胀算法生成更真实的障碍物,不像常规的立方体障碍那么生硬。改radius参数可以控制障碍物大小,color参数直接修改障碍物显示颜色。

主算法部分才是重头戏,看这个带详细注释的A*核心:

while ~isempty(openSet)
    [~, current_idx] = min([openSet.f_cost]);  % 找最小代价节点
    current = openSet(current_idx);
    
    % 到达终点判断(允许z轴误差)
    if norm([current.x, current.y, current.z] - goal_pos) < 1.5
        path = reconstruct_path(current);
        break;
    end
    
    % 生成26邻域(三维全连接)
    neighbors = get_neighbors(current, map);
    
    for k = 1:length(neighbors)
        neighbor = neighbors(k);
        
        % 跳过障碍物和已访问节点
        if neighbor.is_obstacle || ismember(neighbor, closedSet)
            continue;
        end
        
        % 计算新g_cost(考虑高度惩罚)
        tentative_g = current.g_cost + sqrt(sum(([current.x,current.y,current.z]...
            - [neighbor.x,neighbor.y,neighbor.z]).^2)) + altitude_penalty(neighbor.z);
        
        % 更新节点代价
        if ~ismember(neighbor, openSet) || tentative_g < neighbor.g_cost
            neighbor.g_cost = tentative_g;
            neighbor.h_cost = heuristic(neighbor, goal, 'diagonal');
            neighbor.f_cost = neighbor.g_cost + neighbor.h_cost;
            neighbor.parent = current;
            
            if ~ismember(neighbor, openSet)
                openSet(end+1) = neighbor;
            end
        end
    end
end

这里有几个亮点:26邻域搜索让路径更平滑,高度惩罚函数避免飞行器爬升过高,动态代价计算支持实时修改。想要路径更贴近地面?把altitude_penalty函数的权重调大就行。

评价指标部分内置了五种常见分析:

function analyze_path(path)
    lengths = vecnorm(diff([path.x; path.y; path.z], 1, 2)); % 路径长度
    total_length = sum(lengths);
    avg_height = mean([path.z]);
    max_climb = max(diff([path.z]));  % 最大爬升高度
    turning_angles = atan2(vecnorm(diff([diff([path.x])', diff([path.y])'],1,2)),...
        abs(diff([path.z])));  % 转弯角度计算
    energy_cost = total_length * 0.8 + max_climb * 2;  % 能耗模型
    
    fprintf('路径总长:%.2f  平均高度:%.1f\n', total_length, avg_height);
    fprintf('最大爬升:%.1f  平均转弯角:%.1f°\n', max_climb, mean(turning_angles)*180/pi);
    fprintf('综合能耗指数:%.2f\n', energy_cost);
end

这些指标里藏着飞行器能耗模型,把0.8和2这两个系数改成自己的动力参数,就能适配不同机型的需求。

想自定义地图?直接改初始化参数:

map_size = [20 20 15];  % XYZ三维尺寸
start_pos = [1 1 1];    % 起点坐标
goal_pos = [18 17 12];  % 终点坐标
obstacle_color = [0.9 0.2 0.2];  % 障碍物红色
path_color = [0.1 0.8 0.1];      % 路径绿色

把map_size从[20 20 15]改成[50 50 30],立马生成超大三维空间。障碍物颜色调成[0.5 0.5 0.9]就是蓝色障碍,路径颜色改成[1 0.5 0]变成橙色路径。

最后说下怎么扩展功能。比如要加新的评价指标,在analyze_path里加计算逻辑就行。想实现动态障碍物?在主循环里加个障碍物更新函数。代码里留了挺多扩展接口,注释写着"TODO"的地方都是可以魔改的位置。

这个版本的A*在三维栅格地图里最快能跑到0.5秒出路径(20x20x15地图),大尺寸地图建议开启JIT加速。下次考虑加上跳点优化,应该还能快个两三倍。代码已打包成MATLAB函数,需要源码的私信,记得备注来意。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐