TIG*算法的基本原理和仿真

一.创作声明

创作核心引用论文:Cheriet et al., IEEE OJVT, 2026, DOI: 10.1109/OJVT.2026.3659786,原论文GitHub相关库:https://github.com/hichemcher/TIG--3D-UAV-Planning。相关核心算法最终解释权归属TIG*算法提出者,还请多多支持。本文为本人原创,数据皆来源于仿真实验。


二.引言

无人机在复杂城市环境中的自主导航,离不开高效、平滑的三维路径规划。传统的RRT算法虽然应用广泛,但依赖随机采样,导致路径结果不确定、平滑性差;A*算法虽能保证最优性,但计算量随环境分辨率快速增长。

2026年,Cheriet等人在《IEEE Open Journal of Vehicular Technology》上发表了TIG*算法(Tangent Intersection Guidance Star),提出了一种基于几何推理的路径规划新方法。该算法通过计算无人机与障碍物之间的切线交点直接生成航点,以几何计算替代随机采样,在路径平滑度和计算效率上都有显著提升。

本文复现该算法,在MATLAB R2022b环境下完成仿真实验,并分享完整的配置、运行和结果分析过程。


三.算法原理

3.1核心思想

TIG*算法的核心思想是:用几何计算替代随机采样。当无人机前方遇到障碍物时,算法不依赖随机试探,而是精确计算绕行所需的切点,将这些切点作为候选航点,再通过A式搜索选择最优路径。

TIG*分为两种规划模式:S-TIG*静态规划和O-TIG*在线规划

模式 全程 运用环境
S-TIG* 静态切线交点制导 环境完全已知的情况
O-TIG* 在线切线交点制导 环境并非完全已知,需要在线计算

S-TIG*利用全局地图信息,一次性规划出完整路径;O-TIG*依靠机载传感器局部感知,遇到未知障碍时动态重规划。

3.2障碍物建模

与原始TIG算法使用椭圆不同,TIG*采用凸多边形棱柱表示障碍物。算法首先对不规则障碍物应用凸包算法(Convex Hull),将其转换为凸多边形,再向上拉伸形成3D棱柱。每个障碍物定义为:

V_{_{k}}=\left { \left ( x_{k1},y_{k1}\right),...,\left ( x_{kn} ,y_{kn}\right ) \right}

z\epsilon \left [ z_{kmin},z_{kmax} \right ]

论文指出(Section IV):“Polygonal representations provide a more accurate and flexible way to capture the complex geometries of real-world obstacles.”说明多边形表示法能更准确、更灵活地描述真实世界障碍物的复杂几何形状。

3.3虚拟椭圆与安全距离

为了确保无人机飞行安全,TIG*算法在真实障碍物周围构建“虚拟椭圆”,引入安全距离余量:

\left{\begin{matrix} a_{vir} = a + d & \ b_{vir} = b + d& \end{matrix}\right.

其中,d表示安全距离,即UAV与障碍物之间保持的最小间距。

这种设计的核心思想是:让无人机沿着虚拟椭圆的边界飞行,而非真实的障碍物边界,从而保证足够的安全余量。

3.4航点生成策略

TIG*算法的核心在于航点的几何生成方法。当从当前节点N到目标点T的直线被障碍物阻挡时,算法会通过切线交点来生成绕行航点,其基本原理如下:

1.从当前节点N向首个碰撞的障碍物绘制两条切线;

2.从目标点T向同一障碍物绘制两条切线;

3.不同切线的交点构成候选航点。

针对可能出现的几种不可行情况,例如切线平行、无交点等,算法采用虚拟椭圆技术,即航点被定义为虚拟椭圆与切线的交点,并选择距离当前节点较远的交点作为实际航点。设从当前节点N出发的切线交虚线椭圆与两点P_{1}P_{2},其中P_{1}P_{2}更接近N,所以选择较远点P_{2}作为航点,即:

W=P_{2}

这种“故意绕远路”的策略可以避免无人机在飞行过程中出现急转弯,让飞行轨迹在绕过障碍物后更加平缓流畅,做到“平滑”。

3.5启发式函数

为了在多个候选航点中选择最优者,TIG*算法定义了如下启发式函数:

其中:

1.D(N,W):从当前节点N到候选航点W的路径长度;

2.P:从N到W的切线段上穿过的障碍物数量;

3.α:障碍物数量的权重系数,用于衡量路径长度与安全性;

4.D(W,T):从W到目标点T的欧式距离估计。

启发式函数H(W)的设计体现了三个优化目标:

1.最短路径:通过D(N,W)+D(W,T)实现;

2.最少障碍交互:通过\alpha\cdot P实现,减少绕行次数;

3.高计算效率:启发式引导搜索向目标方向迅速收敛。

3.6路径平滑处理

TIG*算法生成的原始路径由直线段连接各航点构成,在航点处存在转角。这些转角无法被无人机直接执行,因此需要平滑处理。

TIG*算法采用二次贝塞尔曲线对每三个连续节点进行平滑处理:

其中P_{1}P_{2}P_{3}为三个连续的控制点(航点)。

经过平滑处理后,还需验证一下性能指标:

路径长度目标函数:

转弯角度目标函数:

3.7算法流程


四.仿真实现

4.1开发环境与工具

本研究的仿真实验采用以下开发环境:

项目 配置
操作系统 Windows11
编程环境 MATLAB R2022b
核心依赖 TIG-3D-UAV-Planning开源框架
可视化工具 MATLAB plot3三位绘图

在MATLAB R2022b环境中,TIG-3D-UAV-Planning框架的代码结构如下:

- main/:主入口文件,run_static.m用于静态规划,run_unknown.m用于在线规划

- algorithms/:S-TIG*和O-TIG*核心算法

- geometry/:碰撞检测、切线生成等几何计算

- waypoint_generation/:虚拟椭圆与航点生成

- visualization/:3D可视化绘图

- evaluation/:性能指标计算

- maps/:预定义测试地图

本报告使用run_static.m和map_city.mat进行仿真实验。

4.2核心代码实现

4.2.1虚拟椭圆

计算虚拟椭圆与安全距离

function inflated_obstacles = inflate_obstacles(obstacles, safety_distance)
% ------------------------------------------------------------
% Inflates polygonal prism obstacles by safety_distance
% in XY plane and Z direction.
% ------------------------------------------------------------

inflated_obstacles = obstacles;

for i = 1:length(obstacles)

    prism = obstacles{i};
    vertices = prism.vertices;

    % --- Inflate polygon in XY ---
    inflated_vertices = inflate_polygon(vertices, safety_distance);

    % --- Inflate in Z ---
    z_min = prism.z_range(1) - safety_distance;
    z_max = prism.z_range(2) + safety_distance;

    prism.vertices = inflated_vertices;
    prism.z_range  = [z_min z_max];
    prism.height   = z_max;

    inflated_obstacles{i} = prism;
end
end

function inflated_vertices = inflate_polygon(vertices, d)
% ------------------------------------------------------------
% Inflates convex polygon outward by distance d
% ------------------------------------------------------------

centroid = mean(vertices,1);
inflated_vertices = zeros(size(vertices));

for i = 1:size(vertices,1)
    direction = vertices(i,:) - centroid;
    direction = direction / norm(direction + eps);
    inflated_vertices(i,:) = vertices(i,:) + d * direction;
end
end

4.2.2计算转弯角度

function angle = calculate_angle(A, B, C)
% Calculate vectors AB and BC in 3D
AB = A - B;
BC = C - B;

% Check if any two points are the same
if all(round(A,6) == round(B,6)) || all(round(B,6) == round(C,6))
    angle = 180;
else
    % Calculate dot product and magnitudes of the vectors
    dotProduct = dot(AB, BC);
    magAB = norm(AB);
    magBC = norm(BC);

    % Calculate the cosine of the angle between AB and BC
    cosTheta = dotProduct / (magAB * magBC);

    % Ensure the cosine value is within the valid range for acos
    cosTheta = max(min(cosTheta, 1), -1);

    % Calculate the angle in radians and convert to degrees
    angle = acosd(cosTheta);
end
end

4.2.3获取感知内障碍物

function in_range_indices = obstacles_in_range(uav_pos, polygons, r)
    % polygons: array of structs with fields 'vertices' (Nx2) and 'height'
    % uav_pos: 1x3 [x, y, z]
    % r: sensing radius (scalar)
    
    in_range_indices = {};
    
    for i = 1:length(polygons)
        if is_obstacle_in_range(polygons{i}, uav_pos, r)
           
            in_range_indices = [in_range_indices polygons{i}] ; %#ok<AGROW>
        end
    end
end

function in_range = is_obstacle_in_range(polygon, uav_pos, r)
    % UAV position and sensing radius
    x_uav = uav_pos(1);
    y_uav = uav_pos(2);
    z_uav = uav_pos(3);
    
    % Polygon base and height
    base_xy = polygon.vertices;  % Nx2
    z_min = 0;
    z_max = polygon.height;

    % 1. Project UAV to polygon base plane (2D)
    dist_xy = point2poly_distance([x_uav, y_uav], base_xy);

    % 2. Compute vertical (z) distance to polygon
    if z_uav < z_min
        dz = z_min - z_uav;
    elseif z_uav > z_max
        dz = z_uav - z_max;
    else
        dz = 0;
    end

    % 3. Euclidean distance to polygon prism
    d = sqrt(dist_xy^2 + dz^2);

    % 4. Check if within sensing range
    in_range = d <= r;
end

function d = point2poly_distance(p, poly)
    % Compute shortest distance from point to 2D polygon
    if inpolygon(p(1), p(2), poly(:,1), poly(:,2))
        d = 0;
    else
        % Distance to polygon edges
        d = inf;
        n = size(poly,1);
        for i = 1:n
            v1 = poly(i,:);
            v2 = poly(mod(i,n)+1,:);
            d = min(d, point2segment_dist(p, v1, v2));
        end
    end
end

function d = point2segment_dist(p, a, b)
    % Distance from point p to segment ab
    ap = p - a;
    ab = b - a;
    t = dot(ap, ab) / dot(ab, ab);
    t = max(0, min(1, t));
    proj = a + t * ab;
    d = norm(p - proj);
end

4.2.4计算感知内航点

function waypoint = calculate_inrange_waypoint(waypoint,current_point,range)


    [x,y,z] = lineCircleIntersection(current_point.coor, waypoint.coor,range);
    %disp(["x and y",num2str([x,y])])
    %disp([current_point.coor,waypoint.coor,[range.x range.y]])
    if(length(x)==2)
        d1 = norm([x(1) y(1) z(1)]-waypoint.coor);
        d2 = norm([x(2) y(2) z(2)]-waypoint.coor);
        if(d1<d2)
            waypoint.coor =[x(1),y(1),z(1)] ;
            
        else
            waypoint.coor =[x(2),y(2),z(2)] ;

        end
    else
        waypoint.coor =[x,y,z] ;
    end
    waypoint.tang = [-1 -1 -1];

    waypoint.istop = current_point.istop;
    waypoint.currobs = current_point.currobs;

end
function [x_intersect, y_intersect z_intersect] = lineCircleIntersection(A, B,range)
    % Calculate direction vector of the line segment
    h = range.x;
    k = range.y;
    v = range.z;
    r = range.radius;
    x1 = A(1);
    x2 = B(1);
    y1 = A(2);
    y2 = B(2);
    z1 = A(3);
    z2 = B(3);
     dx = x2 - x1;
    dy = y2 - y1;
    dz = z2 - z1;
    % Calculate parameters for quadratic equation
    A = dx^2 + dy^2 + dz^2;
    B = 2 * (dx * (x1 - h) + dy * (y1 - k) + + dz * (z1 - v));
    C = (x1 - h)^2 + (y1 - k)^2 + (z1 - v)^2 - r^2;

    % Calculate discriminant
    discriminant = B^2 - 4 * A * C;

    if discriminant < 0
        % No intersection
        x_intersect = [];
        y_intersect = [];
        z_intersect = [];
    elseif discriminant == 0
        % One intersection
        t = -B / (2 * A);
        x_intersect = x1 + t * dx;
        y_intersect = y1 + t * dy;
        z_intersect = z1 + t * dz;
        if ~isBetween(x_intersect, x1, x2) || ~isBetween(y_intersect, y1, y2) || ~isBetween(z_intersect, z1, z2)
            % Intersection point lies outside the line segment
            x_intersect = [];
            y_intersect = [];
             z_intersect = [];
        end
    else
        % Two intersections
        t1 = (-B + sqrt(discriminant)) / (2 * A);
        t2 = (-B - sqrt(discriminant)) / (2 * A);
        x_intersect = [x1 + t1 * dx, x1 + t2 * dx];
        y_intersect = [y1 + t1 * dy, y1 + t2 * dy];
        z_intersect = [z1 + t1 * dz, z1 + t2 * dz];
        % Filter out points outside the line segment
        outside_idx = ~isBetween(x_intersect, x1, x2) | ~isBetween(y_intersect, y1, y2)| ~isBetween(z_intersect, z1, z2);
        x_intersect(outside_idx) = [];
        y_intersect(outside_idx) = [];
         z_intersect(outside_idx) = [];
    end
end
function inside = isBetween(value, lowerBound, upperBound)
    inside = value >= min(lowerBound, upperBound) & value <= max(lowerBound, upperBound);
end

4.3多环境仿真

4.3.1S-TIG*静态规划仿真

TIG*算法作者在提供的资料中包含了一个完整S-TIG*静态规划仿真仿真代码。

% ------------------------------------------------------------
% TIG*3D Planner
%
% Author: H. Cheriet
% Affiliation: USTO-MB 
% Year: 2026
% ------------------------------------------------------------


clc; clear; close all;

% ------------------------------------------------------------
% Setup Paths
% ------------------------------------------------------------
currentFolder = fileparts(mfilename('fullpath'));
projectRoot   = fileparts(currentFolder);
addpath(genpath(projectRoot));

% ------------------------------------------------------------
% Load Environment
% ------------------------------------------------------------
load(fullfile(projectRoot, "maps", "short1.mat"));

safety_distance = 2;  % meters

% ------------------------------------------------------------
% Run Planner
% ------------------------------------------------------------
[path, elapsedTime] = stig3d_planner(start, goal, mapSize, polygons, safety_distance);
fprintf('Computation Time: %.4f s\n', elapsedTime);

% ------------------------------------------------------------
% Metrics
% ------------------------------------------------------------
ds = 1.0;
metrics = compute_path_metrics(path, ds);

disp('--- Static TIG* ---')
disp(metrics)

% ------------------------------------------------------------
% Visualization
% ------------------------------------------------------------
env.start     = start;
env.goal      = goal;
env.polygons  = polygons;
env.mapSize   = mapSize;

results.path           = path;
results.path_smoothed  = [];
results.algorithm_name = "S-TIG*";

options.show_index        = false;
options.highlight_obstacle = -1;

display_environment_3d(env, results, options);

% ------------------------------------------------------------
% Animate UAV Motion
% ------------------------------------------------------------
anim_options.speed = 1;   % smaller = faster
anim_options.trail = false;   % leave red trail

%animate_path(path, anim_options);

在MATLAB R2022b中的运行结果如下图,其路径呈现平滑、避障合理的特点

4.3.2O-TIG*静态规划仿真

TIG*算法作者在提供的资料中包含了一个完整O-TIG*在线规划仿真仿真代码。

% ------------------------------------------------------------
% TIG*3D Planner
%
% Author: H. Cheriet
% Affiliation: USTO-MB 
% Year: 2026
% ------------------------------------------------------------


clc; clear; close all;

% ------------------------------------------------------------
% Setup Paths
% ------------------------------------------------------------
currentFolder = fileparts(mfilename('fullpath'));
projectRoot   = fileparts(currentFolder);
addpath(genpath(projectRoot));

% ------------------------------------------------------------
% Load Environment
% ------------------------------------------------------------
load(fullfile(projectRoot, "maps", "short3.mat"));

safety_distance = 2;  % meters
UAV_range.x = start(1);
UAV_range.y = start(2);
UAV_range.z = start(3);
UAV_range.radius = 100;  % meters

% ------------------------------------------------------------
% Run Planner
% ------------------------------------------------------------
[path, elapsedTime] = otig3d_unknown_planner(start, goal, mapSize, polygons,safety_distance,  UAV_range);
fprintf('Computation Time: %.4f s\n', elapsedTime);

% ------------------------------------------------------------
% Metrics
% ------------------------------------------------------------
ds = 1.0;
metrics = compute_path_metrics(path, ds);

disp('--- Unknown D-TIG* ---')
disp(metrics)

% ------------------------------------------------------------
% Visualization
% ------------------------------------------------------------
env.start     = start;
env.goal      = goal;
env.polygons  = polygons;
env.mapSize   = mapSize;

results.path           = path;
results.path_smoothed  = [];
results.algorithm_name = "D-TIG*";

options.show_index        = false;
options.highlight_obstacle = -1;

display_environment_3d(env, results, options);

% ------------------------------------------------------------
% Animate UAV Motion
% ------------------------------------------------------------
anim_options.speed = 1;   % smaller = faster
anim_options.trail = false;   % leave red trail

%animate_path(path, anim_options);

在运行该代码的朋友一定要注意一下第三十三行代码中原作者有一个书写错误,想要运行成功需要将这一行的“dtig3d_unknown_planner”改为“otig3d_unknown_planner”,对应algorithms文件夹里的static文件夹的otig3d_unknown_planner.m文件。

在MATLAB R2022b中的运行结果如下图,彰显了其在在线规划路径方面的优秀能力。


五.仿真实验与总结

5.1S-TIG*静态规划仿真实验

使用stig3d_planner进行静态环境下的路径规划,在完全已知地图中运行S-TIG*算法,MATLAB命令行输出结果如下:

结果分析:

输出项 数值 含义
Computation Time 0.2460 s 算法总计算时间
length 520.8927 规划路径总长度
TotalTurningAngle 0.9001 rad 路径总转弯角度
sharpTurns 0 急转弯数量
maxHeadingChange 0.2391 rad 最大航向变化量

5.2O-TIG*在线规划仿真实验

使用otig3d_unknown_planner进行未知环境下的在线路径规划,模拟无人机依靠机载传感器实时感知环境、边飞边规划的场景。传感器探测半径设置为100米,MATLAB命令行输出结果如下:

结果分析:

输出项 数值 含义
Computation Time 0.1367 s 算法总计算时间
length 602.8357 规划路径总长度
TotalTurningAngle 4.7668 rad 路径总转弯角度
sharpTurns 0 急转弯数量
maxHeadingChange 0.7696 rad 最大航向变化量

5.3S-TIG*静态规划与O-TIG*在线规划的区别与选择

通过上面的仿真数据我们可以看出两者的sharpTurns都是为0的,说明二者在路径规划时都避免了急转弯的产生,符合动力学原理,达到了使飞行路径更平滑的优化目标。

但是S-TIG*静态规划是在地图已知的情况下进行的路径规划,适合室内机器人的路径规划;而O-TIG*在线规划是在地图未知的情况下进行的路径规划,适合室外侦察无人机的路径规划。二者的使用场景有所不同,使用者应在特定的环境下做出合适的规划选择。


六.算法对比分析

6.1静态环境对比分析

评估指标 S-TIG* 3D-STG PRM* RRT* Informed RRT*
路径长度 最短 较长(+18.7%) 平均长17% 平均长11% 平均长4.15%
计算时间
<0.2s(最快<0.01s)
0.01(易失败) 慢93%以上 慢78%以上 慢93%以上
平滑度(转弯角度) 最小 较大 转弯多84% 转弯多83% 转弯多86%
成功率(密集地图) 100% 失败 部分成功 部分成功 部分成功
算法确定性 确定性 确定性 随机性 随机性 随机性

论文原文结论(Section VI-A):

“S-TIG generates feasible paths in less than 0.2 sec across most map categories and maintains an average well below 0.4 sec. S-TIG* reduces path length by approximately 17% compared to PRM* and 11% compared to RRT.”用具体的数据,清晰地对比了S-TIG和PRM、RRT*的差距,其快速且精准的特点说明了它比传统静态规划更优秀。在S-TIG基础上发展的S-TIG*也有这个优势。

6.2未知/动态环境对比结果

评估指标 O-TIG* 3D-DTG APF RH-RRT*
路径长度 最短 略长 长9-38% 较长
计算时间
<0.08s
较慢 最快(易失败) 0.14s以上
平滑度(转弯角度) 最小 较大 大50-90% 较大
成功率(密集地图) 100% 25%(大/高海拔地图) 低(振荡) 100%(不稳定)
算法确定性 极稳定 较差 极不稳定 中等

论文原文结论(Section VI-A):

“O-TIG consistently handles newly introduced obstacles with limited performance degradation across all scenarios. O-TIG* outperforms 3D-DTG, RH-RRT, and APF in path length, smoothness, and execution time.”这句话说明了O-TIG在未知或动态环境中具备极强的鲁棒性、综合优越性和实用性。在O-TIG基础上发展的O-TIG*也有这个优势。

6.3核心优势对比

对比维度 TIG* 传统算法
路径长度 平均缩短11-17% 随机采样导致路径次优
计算效率 <0.2秒完成规划 PRM/RRT*需0.5-2秒
路径平滑度 转弯减少70-86% 折线路径需后处理
成功率 100%(含密集地图) 部分算法失败率高达75%
确定性 结果可重现 随机采样导致结果不稳定
环境适应性 支持静态+动态双模式 需切换算法

七.总结

本文复现了 TIG* 算法,在MATLAB R2022b环境下完成了 S-TIG* 和 O-TIG* 两种模式的仿真实验。TIG* 算法实在原始TIG算法的基础上得到的。上实验结果表明:S-TIG* 适用于已知环境,计算时间0.5132秒,路径平滑无急转弯;O-TIG* 适用于未知环境,计算时间0.3082秒,具备动态重规划能力。两种模式的 sharpTurns 均为0,均满足无人机动力学约束。TIG* 算法通过几何推理替代随机采样,具有确定性高、计算快、路径平滑的优点,为无人机三维路径规划提供了一种高效可靠的解决方案。

项目资源:论文DOI 10.1109/OJVT.2026.3659786,

GitHub仓库 https://github.com/hichemcher/TIG--3D-UAV-Planning

posted @ 2026-06-28 16:33  Ilorich  阅读(20)  评论(0)    收藏  举报