当前位置:首页>python>我用 Python 手搓了一套无人机编队协同避障 3D 仿真系统,三大算法硬核拆解

我用 Python 手搓了一套无人机编队协同避障 3D 仿真系统,三大算法硬核拆解

  • 2026-06-29 23:38:49
我用 Python 手搓了一套无人机编队协同避障 3D 仿真系统,三大算法硬核拆解

当 12 架无人机同时穿越布满圆柱障碍物的空域,还要保持 V 字编队不散形——这背后是怎样的算法博弈?本文带你从数学原理到工程实现,逐行拆解一个完整的无人机集群仿真系统,并深入探讨每个设计决策背后的控制论、计算几何与多智能体系统理论。


一、为什么要做这个系统?

无人机集群(UAV Swarm)是近年来最火热的研究方向之一。从农业植保到应急救援,从灯光秀到军事侦察,多机协同已经不再是论文里的概念。DARPA 的 OFFSET 项目、Intel 的灯光秀编队、深圳的无人机物流试验——所有这些系统的核心都指向同一个问题:

多架无人机如何在保持编队队形的同时,安全地穿越充满障碍物的复杂空域?

这不是简单的"A 点到 B 点"路径规划。从控制论的视角看,它是一个多目标耦合的约束优化问题,要求同时解决三个本质矛盾:

  • • 目标趋近(Goal Attraction):每架无人机需要飞向各自的编队位置——这是个体目标
  • • 队形保持(Formation Maintenance):机间相对位置关系不能散——这是集体约束
  • • 避障安全(Collision Avoidance):对静态障碍物和其他无人机都要保持安全距离——这是硬约束

这三个目标相互矛盾——追目标要加速,避障要减速转向,保队形要协调。在控制理论中,这类问题被称为 "多目标博弈"(Multi-Objective Game),不存在单一最优解,只能在 Pareto 前沿上做权衡。

我选择了三种经典但思路截然不同的算法来实现和对比:人工势场法(APF)一致性编队控制(Consensus)Boids 集群算法。然后用 Flask + Three.js 搭了一套实时 3D 可视化仿真平台,把整个过程"看得见"。

更重要的是,我想通过这个工程化的实现来回答一个常被忽视的问题:教科书上的算法为什么直接用到实际系统中就会"翻车"?从理论到可工作系统之间的鸿沟,到底需要用哪些工程手段来填平?


二、系统架构:实时仿真的全栈方案

先看看整体架构:

┌─────────────────────────────────────────────────┐│              浏览器 (Three.js 3D)                 ││   ┌─────────┐ ┌─────────┐ ┌──────────────────┐  ││   │ 3D场景   │ │ 控制面板 │ │ 实时数据图表      │  ││   └────┬────┘ └────┬────┘ └────────┬─────────┘  ││        └───────────┼───────────────┘            ││              Socket.IO                          │└────────────────┬────────────────────────────────┘                 │ WebSocket┌────────────────┴────────────────────────────────┐│              Flask + SocketIO                    ││   ┌──────────────────────────────────────────┐   ││   │          Simulation Engine               │   ││   │  ┌──────┐  ┌──────────┐  ┌────────────┐  │   ││   │  │ APF  │  │Consensus │  │   Boids    │  │   ││   │  └──────┘  └──────────┘  └────────────┘  │   ││   │  ┌─────────────────────────────────────┐  │   ││   │  │  障碍物检测 / 碰撞处理 / 物理引擎    │  │   ││   │  └─────────────────────────────────────┘  │   ││   └──────────────────────────────────────────┘   ││   ┌──────────┐                                   ││   │ Airspace │ 空域建模 & 障碍物生成              ││   └──────────┘                                   │└──────────────────────────────────────────────────┘
图:系统整体架构——前端 Three.js 3D 渲染 + 后端 Flask 仿真引擎 + WebSocket 实时通信

技术栈极简但够用:

  • • 后端:Python 3 + Flask + Flask-SocketIO + NumPy
  • • 前端:原生 HTML/CSS + Three.js 3D 渲染 + Socket.IO 实时通信
  • • 通信:WebSocket 双向推送,每帧同步位置、速度、碰撞数据

整个系统只有 6 个 Python 文件,约 1500 行核心代码(不含前端),却实现了一个完整的物理仿真引擎。

隐式状态机:你可能没注意到的设计

系统内部有一个精心设计的隐式有限状态机,每架无人机的生命周经历四个阶段:

  起飞爬升 → 巡航避障 → 到达减速 → 队形收敛  (step<20)   (主循环)    (arrived)   (settle)

这四个阶段的控制策略完全不同:

  • • 起飞爬升:前 20 步施加额外的升力 lift = 1.5 * (1 - step/20),模拟起飞加速
  • • 巡航避障:主仿真循环,三算法各显神通
  • • 到达减速:进入 ARRIVAL_RADIUS=80 范围后,速度强制归零
  • • 队形收敛:独立的 300 步收敛循环,使用渐进式分数控制

为什么需要这个状态机?因为不同阶段的控制目标完全不同。巡航时要"大胆飞",到达后要"精确停"。混在一起,参数就互相矛盾了。


三、空域建模:障碍物不是随便放的

仿真空间设定为 800×600×500 的三维立方体。障碍物建模为圆柱体——这是对建筑物、烟囱、塔架等真实障碍物的合理简化。

class Airspace:    def __init__(self):        rng = np.random.default_rng(SEED)        for _ in range(NUM_OBSTACLES * 4):  # 过采样 4 倍            r = rng.uniform(OBS_MIN_R, OBS_MAX_R)      # 半径 22~40            height = rng.uniform(OBS_MIN_H, OBS_MAX_H)  # 高度 60~180            cx = rng.uniform(220, W - 220)            cz = rng.uniform(100, D - 100)            # 障碍物间距约束:至少相隔 60 单位            ok = True            for k in kept:                dd = np.hypot(cx - k["x"], cz - k["z"])                if dd < r + k["r"] + 60:                    ok = False                    break

为什么是圆柱体而不是球体?

这个选择背后有深层考量。圆柱体的碰撞检测可以降维——在水平面上退化为圆-点碰撞,只需检查二维距离。如果建模为球体或长方体,碰撞检测的复杂度会显著增加:

  • • 圆柱 vs 点:只需检查 sqrt((x-ox)² + (z-oz)²) < r 且 y < h,O(1) 复杂度
  • • 球体 vs 点:需要三维距离检查,且"从上方飞越"的判定更复杂
  • • 长方体 vs 点:需要 6 个面的半空间测试,计算量翻 6 倍

在实时仿真中,碰撞检测每帧要执行 n_drones × n_obstacles × n_substeps 次,复杂度是 O(n·m·s)。降低单次检测的常数因子至关重要。

过采样与间距约束的工程智慧

注意代码中 NUM_OBSTACLES * 4 的过采样策略。这是经典的拒绝采样(Rejection Sampling)——生成 4 倍候选,只保留满足间距约束的。为什么不能直接随机放置?

  1. 1. 种子固定SEED=2026):确保每次仿真的障碍物布局完全一致,这是算法对比实验的控制变量法——没有一致性就没有可信度
  2. 2. 最小间距约束(60 单位):避免障碍物堆叠形成"不可通行区域"。如果两个障碍物间距小于无人机直径(DRONE_RADIUS*2 = 24),就形成了物理上的死区。60 单位的间距确保了至少存在可通行的缝隙
  3. 3. 排除起止区域cx ∈ [220, W-220],避免出发点或终点被障碍物包围

障碍物对编队拓扑的影响

从图论的角度看,障碍物实际上定义了编队可达性的连通性约束。如果障碍物形成了一条不可逾越的"墙",编队就可能需要分裂再合并——这是经典的 "分裂-合并"(Split-and-Merge)问题,属于 NP-hard。本系统通过间距约束避免了这种极端情况,但也因此牺牲了一些真实场景的代表性。


四、三大算法深度拆解

图:三种算法的核心思想对比——APF 基于势能梯度(独立决策)、Consensus 基于图拓扑通信(协调一致)、Boids 基于局部规则(涌现行为)

4.1 人工势场法(APF):最直觉的物理隐喻

人工势场法由 Khatib 于 1986 年提出,核心思想极其优雅:把目标想象成电荷的"负电势阱",把障碍物想象成同极电荷的"排斥场"

无人机在"引力场"和"斥力场"的合力下自然运动——数学上,这等价于在一个势能面上做梯度下降

图:左——人工势场的势能面与梯度下降路径(绿色为目标吸引,红色为障碍物排斥);右——力饱和机制对比(蓝色为本项目的有界力函数,红色为经典 APF 的无限增长力)
F_total = -∇U_attractive - ∇U_repulsive

其中 U_attractive 是关于目标距离的势函数(通常是二次或锥形),U_repulsive 是关于障碍物距离的势函数(通常是反比例或高斯型)。

def apf_accel(airspace, positions, velocities, formation_offsets, goal):    # 1. 有界全局目标引力(质心级别的)    goal_pull = _bounded_goal_pull(goal, centroid)    # 2. 个体目标追踪力(距离自适应)    attr = APF_ATTR_K * to_target / d_target * min(d_target, 150.0) / 150.0    # 3. 雷达避障力(预测式)    obs_force = _radar_obstacle_avoidance(positions[i], velocities[i], obs_array)    # 4. 避障优先级混合(动态权重)    drone_goal_force = _blend_with_obstacle_priority(drone_goal_force, obs_force)    # 5. 机间排斥力(硬约束)    accels += _inter_drone_repulsion(positions, n)

力饱和(Force Saturation):APF 最重要的工程修正

经典 APF 最大的坑是力爆炸局部极小值

力爆炸问题:当目标很远时,引力与距离成正比(二次势场)或为常数(锥形势场)。如果用二次势场 U = ½k·d²,距离 500 单位时力就高达 k·500,这会把无人机加速到极高速度,直接冲入障碍物群。

本项目的解法是力饱和——当距离超过 200 单位时,引力不再增大,保持在 GOAL_PULL_MAX=2.5 的上限:

def _bounded_goal_pull(goal, centroid):    goal_diff = goal - centroid    gd = np.linalg.norm(goal_diff)    if gd < 1e-3:        return np.zeros(3)    # 线性饱和函数:距离 200 以内线性增长,超过 200 恒定    strength = GOAL_PULL_MAX * min(1.0, gd / 200.0)    return strength * goal_diff / gd

这相当于在控制理论中使用了一个饱和非线性环节(Saturation Nonlinearity)。从系统稳定性的角度看,有界力函数保证了系统能量的有界性——无论初始条件如何,加速度始终被限制在 [-MAX_ACC, MAX_ACC] 范围内,这为 Lyapunov 稳定性分析提供了基础。

避障优先级混合:动态权重调整

这是整个 APF 实现中最精妙的部分。传统 APF 的力叠加是简单的向量和 F = F_attr + F_rep,但当两种力量方向相反时(比如目标在障碍物后面),会出现"拉锯战"。

本项目用了一个动态权重混合

def _blend_with_obstacle_priority(goal_force, obs_force):    obs_mag = np.linalg.norm(obs_force)    if obs_mag < 0.5:        return goal_force    # 压制因子:避障力越大,目标力被压制得越厉害    suppression = min(1.0, obs_mag / 4.0)    return goal_force * (1.0 - suppression * 0.85)

当避障力增强时,目标方向的力被主动压制(最多压制 85%)。这实际上实现了一个优先级切换机制

图:左——避障力对目标引力的压制效果(避障力越大,目标力被压制到越低);右——紧迫度非线性响应曲线(乘以 2.5 后截断到 [0.2, 2.0],确保"早做准备")
  • • 安全距离外:suppression ≈ 0,目标力几乎不受影响
  • • 中等距离:suppression ∈ (0, 1),两个力共存但目标力减弱
  • • 紧急距离:suppression → 1,目标力被压制到 15%

这模拟了一个朴素的道理:遇到障碍物时,先保命,再赶路。 从优化理论的角度看,这是一个字典序优化(Lexicographic Optimization)——避障是第一优先级,目标趋近是第二优先级。

APF 的致命弱点:局部极小值

尽管做了力饱和和优先级混合,APF 仍有一个理论上的致命弱点——局部极小值(Local Minima)

想象一个 U 形障碍物,目标在 U 的开口另一端。无人机进入 U 形内部后,斥力从三面把它推回来,引力又把它往里拉,最终它会停在 U 形内部某个力平衡点上,一动不动。

    障碍物         障碍物   ╔══════╗       ╔══════╗   ║      ║       ║      ║   ║      ╚═══════╝      ║   ║    无人机卡在这里     ║   ║         ↓            ║   ╚══════════════════════╝              ↑            目标在对面

这是 APF 的拓扑缺陷,在数学上已被证明无法通过修改势函数来完全消除(Koditschek, 1987)。工程上的解决方案通常是:

  1. 1. 引入随机扰动(模拟退火思想)
  2. 2. 使用 Navigation Function(Rimon-Koditschek 导航函数)
  3. 3. 检测到停滞时切换到其他策略

本项目的"逃生方案"是雷达避障的切向绕行——当检测到即将碰撞时,施加一个切向力把无人机推向障碍物侧面,而不是简单地后退。这相当于在局部极小值附近注入了一个"逃逸方向"。


4.2 一致性编队控制:从图论和控制论的视角看集群

一致性(Consensus)协议是多智能体系统理论的基石,其数学根基在于代数图论(Algebraic Graph Theory)

理论基础:Laplacian 矩阵与收敛性

在理想条件下(无障碍物),一致性协议的收敛性可以用图的 Laplacian 矩阵来分析。设 n 个智能体的通信拓扑用邻接矩阵 A 表示,Laplacian 矩阵 L = D - A(其中 D 是度矩阵),则一致性协议可以写为:

ẋ = -L·x

关键定理:如果通信图是连通的(即 L 的第二小特征值 λ₂ > 0),则所有智能体的状态渐近收敛到初始状态的加权平均。

本项目的"巧妙改造"实际上打破了这个理论框架——一致性力被限制为个体追踪力的 50%:

def consensus_accel(...):    for j in range(n):        if dist < CONS_COMM_RANGE:  # 通信半径 250            desired_gap = offsets[j] - offsets[i]            current_gap = positions[j] - positions[i]            error = current_gap - desired_gap            consensus_force += CONS_POS_K * (-error) * 0.005            consensus_force += CONS_VEL_K * (velocities[j] - velocities[i]) * 0.02    # 一致性力上限:不超过个体力的50%    max_consensus = np.linalg.norm(individual_force) * 0.5    consensus_force = _cap_force(consensus_force, max(max_consensus, 0.5))

这意味着什么?从控制论的角度看,一致性协议不再是主导动力学,而是变成了个体动力学的"微扰项"

增益调度的物理直觉

仔细看一致性协议的两个增益:

  • • CONS_POS_K * 0.005 = 3.0 * 0.005 = 0.015:位置修正增益
  • • CONS_VEL_K * 0.02 = 2.0 * 0.02 = 0.04:速度同步增益

速度同步增益是位置修正增益的约 2.7 倍。这符合控制论中的常识:阻尼(速度反馈)应该比刚度(位置反馈)更强,否则系统会振荡。

想象两个用弹簧连接的无人机:如果弹簧太硬(位置增益大)而阻尼太弱(速度增益小),它们会像弹簧上的小球一样来回振荡。增加速度同步增益相当于增加阻尼,让系统更快稳定。

50% 上限的工程智慧

"一致性力不超过个体力的 50%"——这是一个非常务实的工程妥协。

纯一致性协议在有障碍物时会出问题:为了保持队形,无人机可能硬穿障碍物。因为一致性协议只看"期望间距 vs 实际间距",不关心路径上有没有障碍物。

50% 上限确保了:"保命 > 保队形"。一致性只做轻量协调,不做强制约束。理论上不够"纯粹",但实际效果远优于教科书实现。

从更深层的角度看,这实际上是在实现一种优先级分层控制(Hierarchical Control)

  • • 第一层:个体避障和目标追踪(高带宽,快速响应)
  • • 第二层:编队一致性(低带宽,慢速协调)

这种分层架构在工业控制系统中非常常见——底层控制器处理安全和实时性,上层控制器处理协调和优化。

通信拓扑的影响

代码中的 CONS_COMM_RANGE = 250 定义了通信半径。这意味着通信拓扑是一个距离相关的动态图——当两架无人机距离超过 250 时,它们之间的一致性力消失。

这在理论上可能带来问题:如果编队被障碍物"撕裂"成两部分,两部分之间的一致性约束消失,可能导致编队永久分裂。不过在本项目的空域尺寸(800×500)和 12 架无人机的密度下,这种情况极少发生。


4.3 Boids 集群算法:仿生学的胜利与涌现的数学

1986 年,Craig Reynolds 提出了 Boids 模型,用三条简单规则就能模拟鸟群的涌现行为:

  1. 1. 分离(Separation):离太近的邻居互相排斥
  2. 2. 对齐(Alignment):与邻居保持速度一致
  3. 3. 聚合(Cohesion):向邻居的中心靠拢
def boids_accel(...):    for j in range(n):        if dist < BOIDS_VISION:  # 视野半径 140            if dist < BOIDS_SEP_DIST:  # 分离距离 45                sep += diff / (dist ** 2)       # 反平方排斥            ali += velocities[j]                # 速度对齐            coh += positions[j]                 # 位置聚合    boids_force = BOIDS_SEP_K * sep    boids_force += BOIDS_ALI_K * (ali_avg - velocities[i])    boids_force += BOIDS_COH_K * (coh_center - positions[i])

为什么分离力用反平方而不是线性?

代码中 sep += diff / (dist ** 2) 使用的是反平方排斥力,这模拟了真实物理中的库仑力或万有引力。为什么不用更简单的线性力 F = k·(d₀ - d)

这涉及到一个深刻的物理学原理:反平方力场具有"短程主导"特性——距离减半,力增大 4 倍。这意味着:

  • • 极近距时:分离力爆炸性增长,确保不会碰撞
  • • 中等距离时:分离力温和,不会过度分散
  • • 远距离时:分离力几乎消失,不影响其他规则

而线性力在远距离时仍然有显著的排斥效果,会导致编队"散开"。反平方力的这种非线性特性,使得 Boids 能够在聚合和分离之间找到自然的平衡点

涌现(Emergence)的数学解释

Boids 最迷人的特性是涌现——没有全局指挥者,仅靠局部规则就能产生全局有序的编队行为。这在数学上如何解释?

从统计力学的角度看,Boids 的速度对齐规则实际上是一个Vicsek 模型(Vicsek et al., 1995)的变体。Vicsek 模型证明了:当粒子密度超过某个临界值时,系统会经历一个从无序到有序的相变(Phase Transition)

有序参数 φ = |⟨v_i⟩| / ⟨|v_i|⟩

当 φ → 1 时,所有无人机速度一致(完全有序编队);当 φ → 0 时,速度随机(混乱)。

本项目的 BOIDS_VISION = 140 和 BOIDS_SEP_DIST = 45 实际上在控制这个"有效密度"——视野半径内的平均邻居数决定了系统处于有序相还是无序相。

Boids 的边界约束力

代码中有一段其他两种算法没有的逻辑——边界墙约束力

wm = 50.0  # 边界影响范围accels[:, 0] += np.where(positions[:, 0] < wm, 2.0 / np.maximum(margin_x, 1), 0)accels[:, 0] -= np.where(W - positions[:, 0] < wm, 2.0 / np.maximum(margin_x, 1), 0)

这是因为 Boids 的聚合力天然有"向心"趋势,容易把整个编队推向空域边界。APF 和 Consensus 有明确的目标引力来对抗这种趋势,但 Boids 需要额外的边界反弹力来防止"集体撞墙"。

这暴露了 Boids 的一个本质弱点:它缺乏全局方向感。没有目标引力,Boids 就是一个自组织的"鱼群",而不是有目的的"编队"。


五、雷达主动避障:最硬核的子系统

三种算法共享同一套避障引擎——雷达主动避障系统。这是整个项目技术含量最高的部分,也是教科书和论文中很少详细讨论的。

5.1 核心思路:预测式避障 vs 反应式避障

这是两种根本不同的避障哲学:

反应式避障(Reactive):

if 距离 < 阈值: 施加排斥力

优点:简单快速。缺点:当速度很快时,检测到危险已经来不及了——就像开车时只看车头前方 1 米。

预测式避障(Predictive):

沿当前速度方向预测未来 N 步轨迹if 未来轨迹穿过障碍物: 提前转向

优点:提前预判,从容应对。缺点:计算量更大。

本项目的雷达系统预测 25 步未来轨迹:

RADAR_RANGE = 350.0           # 雷达探测距离RADAR_ANGLE_HALF = np.pi / 3  # 雷达半角 60度(总视场 120度)RADAR_PREDICT_STEPS = 25      # 预测 25 步def _radar_obstacle_avoidance(pos, vel, obs_array):    # 1. 沿当前速度方向预测未来轨迹    for step in range(1, RADAR_PREDICT_STEPS + 1):        fut_pos = pos + vel * t        fut_margin = np.linalg.norm(fut_to_obs) - or_        if fut_margin < DRONE_RADIUS + 15:  # 预测到碰撞!            det_dist = step  # 记录碰撞将在多少步后发生            break    # 2. 计算切向绕行方向    tangential = np.array([-vel_dir_2d[1], vel_dir_2d[0]])    # 3. 根据紧迫度施加转向力 + 制动力    urgency = 1.0 - (det_dist - 1) / RADAR_PREDICT_STEPS    force += RADAR_STEER_K * urgency * steer_3d   # 转向    force += -RADAR_BRAKE_K * urgency * v_radial   # 制动

这就像自动驾驶中的"预碰撞系统":不是等到快撞了才刹车,而是提前 25 步就开始规划绕行路线。

与模型预测控制(MPC)的关系

如果你熟悉最优控制理论,会发现这个雷达系统实际上是模型预测控制(Model Predictive Control, MPC)的极简版本

特性
标准 MPC
本项目的雷达系统
预测时域
N 步
25 步
系统模型
线性/非线性动力学
匀速运动假设
优化目标
最小化代价函数
检测碰撞并转向
控制输出
最优控制序列
切向转向 + 制动
计算复杂度
O(N²) ~ O(N³)
O(N·M) M=障碍物数

标准 MPC 需要求解一个在线优化问题,计算量巨大。本项目用了一个聪明的简化:不做优化,只做碰撞检测 + 启发式转向。这在实时性要求高的场景下非常实用。

图:雷达避障工作流程——沿速度方向预测 25 步轨迹(蓝色点),检测到与障碍物的预测碰撞后,施加切向转向力(绿色路径)和制动力(紫色)

5.2 切向选择:左绕还是右绕?——一个计算几何问题

当预测到碰撞时,系统需要决定向左还是向右绕。这看似简单,实际上是一个经典的计算几何问题

tangential = np.array([-vel_dir_2d[1], vel_dir_2d[0]])  # 速度方向的左切向dot1 = np.dot(det_normal, tangential)dot2 = np.dot(det_normal, -tangential)if dot2 > dot1:    tangential = -tangential  # 选择离障碍物法线更远的方向

算法的核心思想:选择与障碍物法向量夹角更大的切向

为什么要这样做?设障碍物法向量 n 指向无人机(即从障碍物中心指向无人机),两个切向分别是 t_left 和 t_right。算法选择与 n 点积更小的那个方向——即更"背离"障碍物中心的方向。

        t_left ← 点积大 → 不选            ↗    障碍物 → n → 无人机            ↘        t_right ← 点积小 → 选择

这确保了无人机总是朝着远离障碍物中心的方向转弯,而不是贴边飞。这个设计避免了"擦边球"式的危险飞行。

5.3 紧迫度函数:非线性的直觉

urgency = 1.0 - (det_dist - 1) / RADAR_PREDICT_STEPSurgency = max(0.2, min(2.0, urgency * 2.5))

第一行计算的是线性紧迫度:碰撞越近(det_dist 越小),urgency 越大。第二行做了一个非线性变换:乘以 2.5 并截断到 [0.2, 2.0]。

这意味着:

  • • 碰撞在 25 步后:urgency = 0.2(轻微调整)
  • • 碰撞在 13 步后:urgency ≈ 1.25(中等待命)
  • • 碰撞在 1 步后:urgency = 2.0(紧急规避!)

2.5 的乘数确保了紧迫度在预测范围的前半段就已经超过 1.0——系统倾向于"早做准备"而不是"临阵磨枪"

5.4 三层防护网:纵深防御

即使雷达避障已经很强,项目还加了两道"保险",形成了完整的**纵深防御(Defense in Depth)**体系:

第一层:射线-圆柱相交检测(路径级)

在速度应用之前,用射线与圆柱体的解析相交测试来预判:

def _ray_cylinder_intersect(pos_2d, dir_2d, obs_center_2d, obs_r, max_dist):    oc = pos_2d - obs_center_2d    a = np.dot(dir_2d, dir_2d)    b = 2.0 * np.dot(oc, dir_2d)    c = np.dot(oc, oc) - obs_r * obs_r    discriminant = b * b - 4 * a * c    if discriminant < 0:        return False, 0.0    t1 = (-b - sqrt_d) / (2 * a)    return True, t1  # 返回碰撞距离

这是一个经典的**光线追踪(Ray Tracing)**算法——解一元二次方程判断射线是否穿过圆柱的横截面。如果检测到碰撞,就把速度方向偏转到切向。

第二层:速度裁剪(速度级)

在速度更新后、位置更新前,检查当前速度是否会导致下一帧进入障碍物:

next_x = positions[i, 0] + velocities[i, 0] * dtnext_z = positions[i, 2] + velocities[i, 2] * dtnext_margin = sqrt((next_x-ox)² + (next_z-oz)²) - or_if next_margin < safe_margin:    # 消除径向速度分量(刹车)    velocities[i] -= 1.5 * v_radial * normal

如果预测到下一帧会进入危险区域,直接消除朝向障碍物的速度分量。

第三层:硬约束推离(位置级)

最后的位置级硬约束——如果无人机已经"穿进"了障碍物,直接把它推到安全距离之外。最多迭代 8 次来确保收敛:

for _ in range(8):  # 最多 8 次迭代    for i in range(n):        for ob in obs_array:            if margin < hard_margin:                push = or_ + hard_margin - h_dist                positions[i] += normal * push                # 同时消除法向速度                velocities[i] -= 1.8 * v_radial * normal

为什么需要迭代 8 次?因为推出一个障碍物后,可能又"撞入"了另一个。8 次迭代确保了在多障碍物紧邻的情况下也能收敛到安全位置。

图:三层纵深防御——第一层射线检测预判路径碰撞并转向,第二层速度裁剪消除径向分量紧急制动,第三层硬约束将穿透的无人机推出障碍物

这三层构成了 "预测 -> 预防 -> 兜底"的完整安全链

  1. 1. 雷达系统:提前 25 步预测,从容转向
  2. 2. 射线检测:当前帧路径碰撞预判
  3. 3. 速度裁剪:下一帧安全校验
  4. 4. 硬约束推离:最终兜底

六、物理引擎:子步积分与数值稳定性

6.1 六子步积分:解决"隧道效应"

每帧的时间步长 DT=0.35,但物理更新被拆成了 6 个子步:

n_substeps = 6sub_dt = DT / n_substeps  # = 0.0583for _ in range(n_substeps):    _path_obstacle_check(...)    enforce_obstacle_velocity_clip(...)    positions += velocities * sub_dt    enforce_obstacle_constraints(...)

为什么这么做?这是数值积分中经典的**隧道效应(Tunneling Effect)**问题。

假设 MAX_SPEED = 4.5DT = 0.35,则每帧最大位移 = 4.5 × 0.35 = 1.575 单位。而最小障碍物半径是 22,看起来没问题。但如果考虑多步累积,高速无人机可能在两帧之间"穿过"一个薄障碍物。

拆成 6 子步后,每子步最大位移 = 4.5 × 0.0583 = 0.262 单位,远小于任何障碍物的最小尺寸。这就确保了碰撞检测不会漏检。

从数值分析的角度看,这是一种显式欧拉方法(Explicit Euler)的改进版。标准的显式欧拉 x(t+Δt) = x(t) + v·Δt 是一阶精度,误差为 O(Δt²)。拆成子步后,虽然仍然是欧拉方法,但每步的 Δt 更小,累积误差也更小。

计算代价的权衡

6 子步意味着碰撞检测的工作量乘以 6。但考虑到 Python/NumPy 的向量化计算能力,以及只有 12 架无人机和 12 个障碍物,这个代价完全可接受。

理论上,子步数应该根据最大速度和最小障碍物尺寸来动态计算:

n_substeps = ceil(MAX_SPEED * DT / (MIN_OBSTACLE_SIZE / 2))

本项目选择固定 6 子步是一个工程简化,在参数范围内足够安全。

6.2 近障自动减速:自适应速度控制

near_obs_factor = min(1.0, (距离 - 半径) / 80.0)max_spd = MAX_SPEED * (0.3 + 0.7 * near_obs_factor)

这是一个精妙的自适应速度控制

  • • 距离障碍物 > 80 单位:near_obs_factor = 1.0max_spd = MAX_SPEED(全速)
  • • 距离障碍物 40 单位:near_obs_factor = 0.5max_spd = 0.65 × MAX_SPEED(减速)
  • • 距离障碍物 0 单位(贴着):near_obs_factor = 0.0max_spd = 0.3 × MAX_SPEED(最慢)

最慢降到正常速度的 30%——不是 0%,因为完全停止会导致无人机"卡住"。30% 的速度让无人机在穿越狭窄通道时"小心翼翼"但仍能移动。

这个设计与自动驾驶中的安全距离模型异曲同工:速度应该与可用制动距离成正比。距离障碍物越近,留给避障系统的反应时间越少,速度就应该越低。

6.3 加速度饱和与起飞升力

acc_mag = np.linalg.norm(accels, axis=1, keepdims=True)safe_a = np.where(acc_mag > MAX_ACC,                  accels / np.maximum(acc_mag, 1e-9) * MAX_ACC, accels)if step < 20:    lift = 1.5 * (1 - step / 20)    safe_a[:, 1] += lift

加速度被限制在 MAX_ACC = 5.0,这模拟了无人机的推力上限——真实无人机的电机输出是有限的。

起飞阶段额外施加递减的升力 lift = 1.5 * (1 - step/20),从 1.5 线性递减到 0。这模拟了真实无人机的起飞过程——初始需要克服重力加速爬升,到达巡航高度后升力需求减小。


七、编队到达与队形收敛:最后 100 米的精细操作

当无人机到达目标区域后,进入专门的队形收敛阶段。这是整个系统中最容易被忽视、但工程上最微妙的部分。

7.1 两阶段到达判定

# 阶段1:进入到达半径if dist_to_target < ARRIVAL_RADIUS:  # 80 单位    arrived[i] = True# 阶段2:队形位置收敛(在 _settle_at_goal 中)if dist < 0.5:    positions[idx] = target_pos.copy()  # 精确到位    velocities[idx] = 0

为什么不直接要求 dist < 0.5 才算到达?因为如果要求太高,无人机可能在目标附近"绕圈"永远到不了精确位置(特别是 APF 的局部极小值问题)。

两阶段设计:先用宽松的阈值"捕获"无人机,再用专门的收敛算法精确定位。

7.2 渐进式收敛:先快后慢

for settle_step in range(300):    progress_ratio = settle_step / 300    fraction = 0.95 - progress_ratio * 0.3  # 从 0.95 递减到 0.65    _settle_at_goal(positions, velocities, ..., fraction)

这个 fraction 参数控制了每步向目标移动的比例。0.95 意味着每步移动剩余距离的 95%——几乎一步到位。0.65 则更温和。

为什么递减?

  • • 初期(fraction=0.95):无人机刚进入到达区域,位置偏差大,需要快速拉到目标附近
  • • 后期(fraction=0.65):位置已经接近目标,需要避免过冲和振荡

这在控制理论中叫做变增益控制(Variable Gain Control)增益调度(Gain Scheduling)。本质上是用高增益快速消除大误差,用低增益精细处理小误差。

7.3 软碰撞检测:为队形让步

def _enforce_inter_drone_collision_soft(positions, velocities, margin, arrived_mask=None):    for i in range(n):        for j in range(i + 1, n):            dist = np.linalg.norm(diff)            if arrived_mask[i] and arrived_mask[j]:                effective_margin = DRONE_RADIUS * 2  # 12*2=24,只防物理重叠            else:                effective_margin = margin  # 30,正常间距

正常飞行时,机间安全距离是 INTER_DRONE_MARGIN = 30。但编队间距(GAP = 45)减去安全余量后,无人机之间的距离可能只有 20~25。如果用 30 的碰撞阈值,碰撞检测会不断推开精心定位的编队成员,导致队形永远无法收敛。

软碰撞检测的解法:对已到达的无人机,只检查物理重叠(24),不检查间距冲突(30)

这体现了一个深层的工程原则:在不同阶段,约束的严格程度应该不同。飞行时要保守,到位后要精确。


八、五种编队队形:几何设计与拓扑分析

系统支持五种经典编队:

图:五种经典编队队形(星号为领队)——横队、纵队、V 字、楔形和立方体,各有不同的拓扑特性和适用场景
队形
英文名
特点
适用场景
拓扑连通性
横队
Line
所有无人机一字排开
搜索扫描
链式(脆弱)
纵队
Column
前后排列
穿越狭窄通道
链式(脆弱)
V 字
V-Shape
经典 V 字编队
通用巡逻
树形(中等)
楔形
Wedge
三维楔形,有高度差
立体侦察
树形(中等)
立方体
Cube
三维立体编队
全方位监控
网格(强)

从图论的拓扑连通性角度看,不同编队的抗毁性差异巨大:

  • • 链式拓扑(横队/纵队):任何一个中间节点失效,编队就断裂
  • • 树形拓扑(V 字/楔形):只有领头节点失效才会导致分裂
  • • 网格拓扑(立方体):需要多个节点同时失效才会断裂

队形自适应缩放

编队偏移量会根据目标位置自动缩放,确保编队不会超出空域边界:

for lo, hi, avail_neg, avail_pos in [    (min_off[0], max_off[0], avail_x_neg, avail_x_pos),    (min_off[1], max_off[1], avail_y_neg, avail_y_pos),    (min_off[2], max_off[2], avail_z_neg, avail_z_pos),]:    if hi > avail_pos:        scale = min(scale, avail_pos / hi)    if lo < -avail_neg:        scale = min(scale, avail_neg / (-lo))offsets *= scale

这是一个约束满足问题的简化求解:在所有三个维度上同时满足边界约束,取最小缩放比。

同时,无人机数量也会影响间距:

gap = GAP * min(1.0, 12.0 / max(n, 1)) ** 0.3

当无人机数量超过 12 时,间距按 n^(-0.3) 缩放。指数 0.3 是一个经验值——比线性缩放(指数 1.0)更温和,避免了大量无人机时间距过小导致碰撞检测过度干扰。


九、计算复杂度分析:三种算法的效率对比

在实际部署中,计算效率往往是决定性因素。让我们从理论复杂度来分析:

设 n = 无人机数量,m = 障碍物数量,P = 预测步数(25),S = 子步数(6)。

算法
每帧复杂度
瓶颈
优化潜力
APF
O(n·m·P + n²)
雷达预测 O(n·m·P)
空间哈希降至 O(n·P)
Consensus
O(n² + n·m·P)
邻居搜索 O(n²)
通信图预构建
Boids
O(n² + n·m·P)
邻居搜索 O(n²)
空间哈希降至 O(n)

当 n 较小时(<50),三种算法的差异不大。但当 n 增长到数百或数千时,O(n²) 的邻居搜索会成为瓶颈。

**空间哈希(Spatial Hashing)**是标准的优化手段:将空间划分为网格,每架无人机只搜索相邻网格中的邻居。这可以把 Boids 的复杂度从 O(n²) 降到接近 O(n)。

不过对于本项目的 12 架无人机规模,O(n²) 完全不是问题——12² = 144 次比较,微秒级完成。

雷达避障的优化空间

雷达避障系统当前对每架无人机检查所有障碍物,复杂度 O(n·m·P)。一个优化方向是空间分区:预先计算每个位置附近的障碍物列表,避免全局遍历。另一个方向是距离预筛选:先检查无人机到障碍物中心的距离,如果大于 RADAR_RANGE + 障碍物半径 就跳过。

代码中已经有这个预筛选:

if margin >= RADAR_RANGE:    continueif angle > RADAR_ANGLE_HALF and margin > 40:    continue

这两个条件大幅减少了实际需要预测的障碍物数量。


十、实时可视化:48000 行的前端

前端是一个 48KB 的单文件 HTML,包含:

  • • Three.js 3D 场景:无人机模型、障碍物圆柱体、地面网格、目标标记
  • • 实时 HUD:步数、到达数、碰撞数、编队误差
  • • 双面板 UI:左侧控制面板 + 右侧数据面板
  • • Chart.js 图表:编队误差曲线、速度曲线、到达率统计
  • • 算法对比模式:三种算法同时运行,并排对比结果
  • • 自定义终点:通过滑块实时调整目标点位置

WebSocket 每帧推送的数据包括:

{    "step": 42,    "positions": [[x, y, z], ...],    "arrived": [true,false, ...],    "collisions": 0,    "form_error": 12.34,    "n_arrived": 5}

通信效率

每帧数据量约为 n × 3 × 8 bytes (positions) + n bytes (arrived) + 20 bytes (metadata) ≈ 400 bytes(12 架无人机)。以 30fps 的推送频率计算,带宽需求仅 12KB/s——WebSocket 完全胜任。

后端的推送频率由仿真速度决定。每帧 time.sleep(0.002) 意味着最快约 500fps 的推送能力,但实际受限于计算速度。


十一、算法对比:谁更强?

三种算法各有千秋,适用场景截然不同:

维度
APF
Consensus
Boids
到达率
中高
中高
队形精度
中高
避障安全
中高
中高
计算效率
最高
通信依赖
需要邻居通信
仅局部感知
可扩展性
O(n·m)
O(n²)
O(n²)→O(n)
理论基础
势能面梯度下降
代数图论+Lyapunov
统计力学相变

深入对比分析

APF 的优势与局限

  • • 优势:无需机间通信,每架无人机独立决策,适合通信受限场景
  • • 局限:局部极小值是理论硬伤,无法通过参数调优完全解决
  • • 最适合:稀疏障碍物、点对点导航

Consensus 的优势与局限

  • • 优势:队形精度最高,有严格的收敛性理论保证
  • • 局限:通信拓扑必须保持连通,否则编队分裂
  • • 最适合:通信良好、队形精度要求高的场景

Boids 的优势与局限

  • • 优势:纯局部感知,不需要任何通信基础设施,最易扩展
  • • 局限:编队精度最低,聚合力可能导致集体撞墙
  • • 最适合:大规模集群、通信不可用场景

混合策略的可能性

一个有趣的方向是自适应混合:在开阔区域用 Boids(高效),接近障碍物时切换到 APF(安全),到达目标后用 Consensus(精确)。这需要设计一个状态切换逻辑和平滑过渡机制。


十二、工程启示:教科书 vs 真实世界

这个项目最大的价值不在于算法有多新,而在于展示了从教科书算法到可工作系统之间的巨大鸿沟,以及如何用工程手段填平它。让我把这些工程智慧系统化:

1. 力饱和——防止任何一个力分量爆炸

教科书:F = k · x(线性)工程:F = k · min(x, x_max)(饱和非线性)

为什么:线性力在极端条件下会产生荒谬的加速度,导致数值不稳定或物理穿越。

2. 优先级混合——避障 > 保队形 > 追目标

教科书:所有力简单叠加 F = F1 + F2 + F3工程:高优先级的力压制低优先级的力

为什么:当两个力方向矛盾时,简单叠加会导致"拉锯"和振荡。优先级混合确保了关键任务(安全)始终被执行。

3. 三层防护——预测 → 速度裁剪 → 位置硬约束

教科书:一种碰撞检测方法就够了工程:每一层都可能失效,所以要有冗余

为什么:预测可能漏检(速度方向变化),速度裁剪可能不够(加速度太大),只有位置硬约束是最终的"安全网"。

4. 子步积分——消除隧道效应

教科书:x += v · dt工程:for sub in range(6): x += v · dt/6

为什么:大时间步 + 高速度 = 穿越薄障碍物。子步积分是最简单有效的解决方案。

5. 渐进收敛——到达后不急着"锁死"

教科书:if dist < threshold: arrived = True工程:先宽松捕获,再渐进精调

为什么:过高的精度要求会导致"永远到不了"(Zeno 效应),而直接锁死会在有扰动时产生突变。

6. 软碰撞——对已编队的无人机放宽间距

教科书:统一的安全距离工程:根据状态动态调整安全距离

为什么:编队位置是精心规划的,用正常间距去检查会破坏编队。只在真正危险时(物理重叠)才干预。

7. 隐式状态机——不同阶段用不同策略

教科书:一个控制器跑到底工程:起飞、巡航、到达、收敛四阶段分别处理

为什么:不同阶段的控制目标相互矛盾。混在一个控制器里,参数会打架。


十三、与前沿研究的连接

本系统虽然代码精简,但其设计思路与当前无人机集群研究的前沿方向高度一致:

ORCA(Optimal Reciprocal Collision Avoidance)

ORCA 是目前多智能体避障的"黄金标准"算法,其核心思想是:每个智能体在速度空间中选择一个速度,使得与其他智能体的碰撞时间最大化。本项目的"雷达预测 + 切向转向"本质上是 ORCA 的一种启发式简化——不做精确的速度空间优化,而是用预测碰撞 + 切向绕行的直觉方法达到类似效果。

深度强化学习(DRL)方法

近年来,用深度强化学习训练无人机集群的策略越来越流行(如 PRM-RL、CrowdNav)。DRL 的优势是能学到复杂非线性策略,劣势是缺乏可解释性和安全保证。本项目的方法是完全可解释的——每个力分量都有明确的物理含义,这对于安全关键应用(如载人无人机)至关重要。

分布式模型预测控制(DMPC)

DMPC 是 Consensus 协议的"升级版"——每个智能体不仅考虑当前状态,还预测未来 N 步并做联合优化。本项目的一致性协议可以看作 DMPC 的一步近似——只看当前误差,不做多步预测。


十四、如何运行

# 安装依赖pip install flask flask-socketio numpy# 启动系统python app.py# 浏览器访问# http://127.0.0.1:5000

打开浏览器,选择算法、编队队形、无人机数量,点击"开始仿真",就能实时看到无人机编队穿越障碍物的 3D 动画。还可以点击"算法对比"同时运行三种算法进行 PK。


结语

这个项目的代码量不大,但麻雀虽小五脏俱全。它涵盖了多智能体系统、势场规划、一致性控制、仿生集群、碰撞检测、物理仿真等多个领域的核心知识点。

更重要的是,它揭示了一个常被学术文献忽略的真相:算法的理论是冰山的一角,让算法在真实(或仿真)环境中稳健运行,才是冰山水面下的功夫。 力饱和、优先级混合、三层防护、子步积分、渐进收敛、软碰撞、状态机——这些都不是论文里会重点写的内容,但每一个都是让系统真正"跑起来"的关键。

如果你也在做多无人机协同相关的研究或开发,希望这篇文章能给你一些工程实现上的启发。也欢迎在评论区讨论:如果让你来设计,你会如何在理论优美性和工程实用性之间做取舍?


如果觉得有用,欢迎点赞、在看、转发三连

完整代码已开源,获取方式见评论区。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 06:25:04 HTTP/2.0 GET : https://f.mffb.com.cn/a/501408.html
  2. 运行时间 : 0.211923s [ 吞吐率:4.72req/s ] 内存消耗:4,629.22kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=1a7632be747145a21eb204a0ff96f192
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000588s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000617s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.002856s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.002191s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001487s ]
  6. SELECT * FROM `set` [ RunTime:0.002797s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001498s ]
  8. SELECT * FROM `article` WHERE `id` = 501408 LIMIT 1 [ RunTime:0.013650s ]
  9. UPDATE `article` SET `lasttime` = 1783031104 WHERE `id` = 501408 [ RunTime:0.021071s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.005480s ]
  11. SELECT * FROM `article` WHERE `id` < 501408 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.009303s ]
  12. SELECT * FROM `article` WHERE `id` > 501408 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.010638s ]
  13. SELECT * FROM `article` WHERE `id` < 501408 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.006033s ]
  14. SELECT * FROM `article` WHERE `id` < 501408 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.023721s ]
  15. SELECT * FROM `article` WHERE `id` < 501408 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.025677s ]
0.215884s