一、A_star算法简介
0 引言
随着现代技术的发展,飞行器种类不断变多,应用也日趋专一化、完善化,如专门用作植保的大疆PS-X625无人机,用作街景拍摄与监控巡察的宝鸡行翼航空科技的X8无人机,以及用作水下救援的白鲨MIX水下无人机等,决定飞行器性能主要是内部的飞控系统和外部的路径规划问题。就路径问题而言,在具体实施任务时仅靠操作员手中的遥控器控制无人飞行器执行相应的工作,可能会对操作员心理以及技术提出极高的要求,为了避免个人操作失误,进而造成飞行器损坏的危险,一种解决问题的方法就是对飞行器进行航迹规划。
飞行器的测量精度,航迹路径的合理规划,飞行器工作时的稳定性、安全性等这些变化对飞行器的综合控制系统要求越来越高。无人机航路规划是为了保证无人机完成特定的飞行任务,并且能够在完成任务的过程中躲避各种障碍、威胁区域而设计出最优航迹路线的问题。常见的航迹规划算法如图1所示。
图1 常见路径规划算法
文中主要对无人机巡航阶段的航迹规划进行研究,假设无人机在飞行中维持高度与速度不变,那么航迹规划成为一个二维平面的规划问题。在航迹规划算法中,A算法计算简单,容易实现。在改进A算法基础上,提出一种新的、易于理解的改进A算法的无人机航迹规划方法。传统A算法将规划区域栅格化,节点扩展只限于栅格线的交叉点,在栅格线的交叉点与交叉点之间往往存在一定角度的两个运动方向。将存在角度的两段路径无限放大、细化,然后分别用两段上的相应路径规划点作为切点,找到相对应的组成内切圆的圆心,然后作弧,并求出相对应的两切点之间的弧所对应的圆心角,根据下式计算出弧线的长度
式中:R———内切圆的半径;
α———切点之间弧线对应的圆心角。
1 A*算法概述
A算法是在Dijstar算法的基础上引入的启发式函数,通过定义的代价函数来评估代价大小,从而确定最优路径。A算法的代价函数
式中:f(x,y)———初始状态X0(x0,y0)到达目标状态X1(x1,y1)的代价估计;
g(x,y)———状态空间中从初始状态X0(x0,y0)到状态N(x1,y1)的实际代价;
h(x,y)———从状态N(x1,y1)到目标状态X1(x1,y1)最佳路径的估计代价。
要找到最短路径的实质是找到f(x,y)的最小值,其中在式(2)中寻找最短路径的关键在于求估计代价h (x,y)值。设系数λ表示状态N(x1,y1)到X1(x1,y1)最优距离,如果λ<h(x,y),搜索范围小,不能保证得到最优解;λ>h(x,y),搜索范围大,费时,但能找到最优解;λ=h(x,y),搜索到最短路径。其中h(x,y)一般用欧几里德距离(式(3))或者绝对值距离(式(4))计算。
A算法是以起始点为中心,周围8个栅格的中心为下一步预选,并不断地计算预选位置的f(x,y)值,其中f(x,y)值最小的作为当前位置,依次逐层比较,直到当前位置的临近点出现目标点为止,其最小单元如图2所示。
图2 最小单元
A算法的流程如下:
1)创建开始节点START,目标节点TARGET、OPEN列表、CLOSE列表、CLOSE列表初始为空;
2)将START加入到OPEN列表;
3)检查OPEN列表中的节点,若列表为空,则无可行路径;若不为空,选择使f(x,y)值最小的节点k;
4)将节点k从OPEN中去除,并将其添加到CLOSE中,判断节点k是否目标节点TARGET,若是,则说明找到路径;若不是,则继续扩展节点k,生成k节点的子节点集,设q为k的子节点集,对所有节点q计算相应的f(x,y)值,并选择f(x,y)值最小的节点,将该节点放入CLOSE列表中;
5)跳到3),直到算法获得可行路径或无解退出。
二、部分源代码
%Main
clc
clear
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Grid and path parameters
%Grid size [y,x,z] and resolution
sizeE=[80 80 20];
d_grid=1;
%Starting point
x0=5;
y0=7;
z0=12;
%Arrival point
xend=68;
yend=66;
zend=6;
%Number of points with low elevation around start and end point area
n_low=3;
%A* or Theta* cost weights
kg=1;
kh=1.25;
ke=sqrt((xend-x0)^2+(yend-y0)^2+(zend-z0)^2);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Map definition
%Average flight altitude
h=max(z0,zend);
%Points coordinates in [y,x,z] format
P0=[y0 x0 z0];
Pend=[yend xend zend];
%Generate map
[E,E_safe,E3d,E3d_safe]=grid_3D_safe_zone(sizeE,d_grid,h,P0,Pend,n_low);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Path generation
%Store gains in vector
K=[kg kh ke];
%Measure path computation time
tic
%Generate path (chose one)
% [path,n_points]=a_star_3D(K,E3d_safe,x0,y0,z0,xend,yend,zend,sizeE);
% [path,n_points]=theta_star_3D(K,E3d_safe,x0,y0,z0,xend,yend,zend,sizeE);
[path,n_points]=lazy_theta_star_3D(K,E3d_safe,x0,y0,z0,xend,yend,zend,sizeE);
T_path=toc;
%Path waypoints partial distance
%Initialize
path_distance=zeros(n_points,1);
for i=2:n_points
path_distance(i)=path_distance(i-1)+sqrt((path(i,2)-path(i-1,2))^2+(path(i,1)-path(i-1,1))^2+(path(i,3)-path(i-1,3))^2);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Plot
%Map grid
x_grid=1:d_grid:sizeE(2);
y_grid=1:d_grid:sizeE(1);
%Path on safe map
figure(1)
surf(x_grid(2:end-1),y_grid(2:end-1),E_safe(2:end-1,2:end-1))
hold on
plot3(x0,y0,z0,'gs')
plot3(xend,yend,zend,'rd')
plot3(path(:,2),path(:,1),path(:,3),'yx')
plot3(path(:,2),path(:,1),path(:,3),'w')
axis tight
axis equal
view(0,90);
colorbar
%Path on standard map
figure(2)
surf(x_grid(2:end-1),y_grid(2:end-1),E(2:end-1,2:end-1))
hold on
plot3(x0,y0,z0,'gs')
plot3(xend,yend,zend,'rd')
plot3(path(:,2),path(:,1),path(:,3),'yx')
plot3(path(:,2),path(:,1),path(:,3),'w')
axis tight
axis equal
view(0,90);
colorbar
%Path height profile
figure(3)
plot(path_distance,path(:,3))
grid on
xlabel('Path distance')
ylabel('Path height')
%A star algorithm
function [path,n_points]=a_star_3D(K,E3d_safe,x0_old,y0_old,z0_old,xend_old,yend_old,zend_old,sizeE)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Cost weights
kg=K(1);
kh=K(2);
ke=K(3);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Algorithm
%If start and end points are not integer, they are rounded for the path genertion. Use of floor and ceil so they are different even if very close
x0=floor(x0_old);
y0=floor(y0_old);
z0=floor(z0_old);
xend=ceil(xend_old);
yend=ceil(yend_old);
zend=ceil(zend_old);
%Initialize
%Size of environment matrix
y_size=sizeE(1);
x_size=sizeE(2);
z_size=sizeE(3);
%Node from which the good neighbour is reached
came_fromx=zeros(sizeE);
came_fromy=zeros(sizeE);
came_fromz=zeros(sizeE);
came_fromx(y0,x0,z0)=x0;
came_fromy(y0,x0,z0)=y0;
came_fromz(y0,x0,z0)=z0;
%Nodes already evaluated
closed=[];
%Nodes to be evaluated
open=[y0,x0,z0];
%Cost of moving from start point to the node
G=Inf*ones(sizeE);
G(y0,x0,z0)=0;
%Initial total cost
F=Inf*ones(sizeE);
F(y0,x0,z0)=sqrt((xend-x0)^2+(yend-y0)^2+(zend-z0)^2);
%Initialize
exit_path=0;
%While open is not empy
while isempty(open)==0 && exit_path==0
%Find node with minimum f in open
%Initialize
f_open=zeros(size(open,1),1);
%Evaluate f for the nodes in open
for i=1:size(open,1)
f_open(i,:)=F(open(i,1),open(i,2),open(i,3));
end
%Find the index location in open for the node with minimum f
[~,i_f_open_min]=min(f_open);
%Location of node with minimum f in open
ycurrent=open(i_f_open_min,1);
xcurrent=open(i_f_open_min,2);
zcurrent=open(i_f_open_min,3);
point_current=[ycurrent, xcurrent, zcurrent];
%Check if the arrival node is reached
if xcurrent==xend && ycurrent==yend && zcurrent==zend
%Arrival node reached, exit and generate path
exit_path=1;
else
%Add the node to closed
closed(size(closed,1)+1,:)=point_current;
%Remove the node from open
i_open_keep=horzcat(1:i_f_open_min-1,i_f_open_min+1:size(open,1));
open=open(i_open_keep,:);
%Check neighbour nodes
for i=-1:1
for j=-1:1
for k=-1:1
%If the neighbour node is within grid
if xcurrent+i>0 && ycurrent+j>0 && zcurrent+k>0 && xcurrent+i<=x_size && ycurrent+j<=y_size && zcurrent+k<=z_size
%If the neighbour node does not belong to open and to closed
check_open=max(sum([ycurrent+j==open(:,1) xcurrent+i==open(:,2) zcurrent+k==open(:,3)],2));
check_closed=max(sum([ycurrent+j==closed(:,1) xcurrent+i==closed(:,2) zcurrent+k==closed(:,3)],2));
if isempty(check_open)==1
check_open=0;
end
if isempty(check_closed)==1
check_closed=0;
end
if check_open<3 && check_closed<3
%Add the neighbour node to open
open(size(open,1)+1,:)=[ycurrent+j, xcurrent+i, zcurrent+k];
%Evaluate the distance from start to the current node + from the current node to the neighbour node
g_try=G(ycurrent,xcurrent,zcurrent)+sqrt(i^2+j^2+k^2);
%If this distance is smaller than the neighbour distance
if g_try<G(ycurrent+j,xcurrent+i,zcurrent+k)
%We are on the good path, save information
%Record from which node the good neighbour is reached
came_fromy(ycurrent+j,xcurrent+i,zcurrent+k)=ycurrent;
came_fromx(ycurrent+j,xcurrent+i,zcurrent+k)=xcurrent;
came_fromz(ycurrent+j,xcurrent+i,zcurrent+k)=zcurrent;
三、运行结果
四、matlab版本及参考文献
1 matlab版本 2014a
2 参考文献 [1] 包子阳,余继周,杨杉.智能优化算法及其MATLAB实例(第2版)[M].电子工业出版社,2016. [2]张岩,吴水根.MATLAB优化算法源代码[M].清华大学出版社,2017. [3]巫茜,罗金彪,顾晓群,曾青.基于改进PSO的无人机三维航迹规划优化算法[J].兵器装备工程学报. 2021,42(08) [4]邓叶,姜香菊.基于改进人工势场法的四旋翼无人机航迹规划算法[J].传感器与微系统. 2021,40(07) [5]马云红,张恒,齐乐融,贺建良.基于改进A*算法的三维无人机路径规划[J].电光与控制. 2019,26(10) [6]焦阳.基于改进蚁群算法的无人机三维路径规划研究[J].舰船电子工程. 2019,39(03)