【论文解析】DUCPP —— 当路不知道能不能走,让无人机先去探路

📄 论文解析:DUCPP ------ 当路不知道能不能走,让无人机先去探路

论文全名: Dynamic UGV-UAV Cooperative Path Planning in Uncertain Environments
发布时间: 2026年4月(arXiv:2604.25267v1)
机构: 北卡罗来纳大学夏洛特分校计算机科学系

一、问题背景:你以为走得通的路,走一半才发现是死路

想象一个灾后救援场景:地震过后,救援车必须穿越城市道路网络运送物资。城市地图是有的,但地图上存在的路,不代表现在能走------有的路段被建筑物碎石堵死,有的桥梁已经垮塌,有的积水过深无法通行。

问题的核心难在:

  • 路能不能走,只有到了现场才知道。导航软件不知道,调度中心不知道,司机出发前也不知道。
  • 如果走到一半发现断路,只能原路返回重规划,时间白白浪费
  • 城市路网错综复杂,哪条路最值得先去探查,是个困难决策

这就是论文所研究的动态不确定环境下的 UGV-UAV 协同路径规划(Dynamic UGV-UAV Cooperative Path Planning,DUCPP)问题的出发点。

解题思路其实朴素而直觉------既然无人车在地面走路慢、探路受限,那就让无人机飞在前头先看清楚,再把信息实时传回给无人车,指导它选最优路线。

但"让无人机先探路"说起来简单,做起来有一连串问题:

  • 道路那么多,无人机先探哪条?
  • 无人车在走,无人机要飞去哪里探路才最有价值?
  • 如果有多架无人机,怎么分工才不重复?
  • 探路途中发现新的断路,双方如何实时调整?

DUCPP 正是对这一完整问题的系统性研究。

二、应用场景:不只是救灾,是一切"走之前不知道能不能走"的情形

应用场景 不确定性来源
灾害响应 地震、洪水、山火造成路段损毁,实时状态未知
应急物资运输 战时或极端天气下,公路网络动态损毁,驾驶员需实时引导
搜救行动 救援队需穿越废墟区,地面可通行性完全未知
军事后勤 敌方破坏或地雷封锁,部分路段状态危险或不可通行
极端天气下的配送 冰雪封路、洪涝积水,哪段路还能走只有实地确认才知道

值得注意的是,论文的方法也可以用于给人类驾驶员规划路线------无人机探路,无人车或人开的车跟随导航结果走。这让 DUCPP 的应用范围超出了纯机器人领域,具有实际的工程部署价值。

三、问题形式化:一张"地图上有坑"的图论问题

论文将道路网络建模为图 G = (V, E),节点是路口,边是路段。每条边有一个存在概率(existence probability,范围 0.6, 1.0),表示这条路可通行的可能性。

关键的建模细节有几点,很有现实意义:

不到现场不知道 :边的状态(通/断)只有当 UGV 或 UAV 实际到达损毁点时才会被发现,而损毁点可能在路段中间,不一定在节点处。这比经典的"加拿大旅行者问题"(CTP)更贴近现实------CTP 假设到达节点就能知道所有邻边状态,而 DUCPP 要求真正"到达"才知道。

UGV 和 UAV 的移动方式不同

  • UGV 只能沿图的边行驶
  • UAV 可以沿边飞行(探路),也可以在任意两点之间直线飞行(deadhead),后者让 UAV 能快速奔赴需要探查的路段

目标:最小化 UGV 到达目的地的总行驶时间(包括因断路绕行损失的时间)。

四、方法:六种策略,一场"谁更聪明"的比赛

论文设计了一套统一的框架,核心循环是:路径规划 → 边分配(给 UAV) → 行驶/巡查 → 发现新情况 → 重规划。在这个框架下,论文提出并比较了六种策略:

4.1 完美知识(Perfect Knowledge)------ 理论下界

假设所有路段状态预先已知,用 Dijkstra 找最短路径。这是任何策略都无法突破的理论最优下界,用来衡量其他策略的差距。

4.2 仅 UGV(UGV-only)------ 最笨的基线

没有无人机,UGV 靠自己走,遇到断路回头重规划。这是最差的情形,对应的是"没有空中支援的救援车",也是所有 UAV 辅助策略对比的基准。

4.3 基于 Kemeny 常数(Kemeny Strategy)

从图论出发,预计算每条边的"重要性"------具体用的是一种基于 Kemeny 常数的边中心性指标:移除某条边后图的 Kemeny 常数越大,说明这条边越关键(一旦断了影响越大)。UAV 优先去探查 UGV 路径上重要性最高的未探边。

这个方法的缺点是 Kemeny 常数只在最开始计算一次,不随图更新而调整,灵活性有限。

4.4 基于 k 最短路径

用 Yen 算法找从当前位置到目的地的 k 条最短路,UAV 优先探查在这 k 条路中出现频率最高的未探边------出现次数越多,说明这条边越是"共同瓶颈",探清楚价值越大。这个方法动态性更好,但计算量随 k 增大。

4.5 最大概率最短路(MPSP)

结合每条边的存在概率,找的不是单纯最短路,而是既短又最可能能走通的路径。UAV 专去探查路径上存在概率最低的边(最有可能断的那一条)。

这个策略在直觉上很合理:不确定性最高的边最值得先确认。

4.6 双向策略(Bidirectional)------ 论文的主角

这是论文最核心的创新策略,逻辑极其简洁:

UGV 从起点向终点走;UAV 从终点端开始,沿 UGV 规划路径"反向"逐条探查。

UAV 从目的地附近开始探查,沿 UGV 的规划路径往回检查;UGV 同时从起点出发前进。两者"相向而行",当两者汇合时,整条路径的关键路段都已经确认安全(或找到了备用路线)。

这个设计的聪明之处在于:

  • UAV 通常从目的地附近的相邻边开始探查,这些边彼此连接,UAV 不需要长途奔袭,大幅减少了 UAV 的"空飞"时间
  • 对比其他策略,UAV 经常需要飞去图的其他位置探查"高优先级"边,但飞过去就已经花了很多时间
  • 计算复杂度低,和 Dijkstra 同量级 O((V+E)logV)

4.7 多 UAV 双向策略

将双向策略扩展到 k 架 UAV:用 Yen 算法找 k 条最短路,每架 UAV 从对应路径的终点反向探查,且每条边只分配一架 UAV,避免重复探查(同时假设飞不同高度规避碰撞)。

五、实验结果:数字告诉你双向策略赢在哪里

实验基于 OpenStreetMap 全球 50 大城市的真实路网,每个城市有小图(1km×1km)和大图(3km×3km),各随机生成 50 个实例,共计100 张路网 × 50 个实例 = 5000 个测试场景,规模可观。

部分关键结论(UAV 速度 40m/s,UGV 速度 20m/s):

策略 东京(小图)UGV 用时 拉各斯(大图)UGV 用时
完美知识(下界) 8.9s 48.3s
仅 UGV 31.4s 317.4s
双向策略 21.1s 170.6s
7 架 UAV(双向) 17.2s 138.3s

双向策略在大图上相比仅 UGV 策略平均节省 38.4% 的行驶时间(UAV:UGV 速度比 2:1 时);多 UAV 进一步压缩时间,但计算量随 UAV 数量显著上升。

特别有意思的一个趋势:地图越大,UAV 的优势越明显。大图中断路造成的绕行代价更高,UAV 提前探路的价值也更大。这也说明该方法在真实大城市场景中具有实际意义。

六、创新点:论文的新在哪里?

✦ 创新一:更现实的断路建模

与以往研究相比,DUCPP 明确区分了"边成本不确定"和"边完全不可通行"两种情况,并规定损毁点可能在路段中间而非节点处。这让问题更贴近真实灾害场景,也使得策略设计更有挑战性。

✦ 创新二:双向协同策略的设计

将经典双向搜索思路引入 UAV-UGV 多智能体场景,让 UAV 从终点反向探查这一设计,实现了"以最低飞行代价覆盖最关键路段"的效果。这个思路直觉清晰,但此前并没有人在 UAV 辅助 UGV 的场景中这样做过。

✦ 创新三:多策略系统比较

论文不是只提一个方法,而是设计并横向比较了 6 种策略(含两个基线),在时间效率和计算复杂度两个维度上进行全面评估,为后续研究提供了清晰的方法谱系。

✦ 创新四:多 UAV 扩展与分工机制

通过 k 条最短路 + 每条路分配一架 UAV 的设计,优雅地解决了多 UAV 的任务分配问题,保证无重复探查,且碰撞规避通过分配不同飞行高度简洁处理。

七、不足之处:诚实面对局限

⚠ 不足一:通信假设过于理想

论文假设无线通信无延迟、无丢包,UAV 发现的断路信息瞬间传达给 UGV。在实际灾害现场,通信基础设施往往受损,信号中断是常态而非例外。论文自己也承认这是需要解决的实际问题,但没有给出解决方案。

⚠ 不足二:UAV 没有能量限制

论文完全忽略了 UAV 的电池续航约束。现实中无人机的飞行时间通常只有 20-40 分钟,大城市路网探查任务可能远超这个时限。没有能量约束,多 UAV 的调度策略就是在一个简化的理想世界里运行。

⚠ 不足三:UAV 直线飞行假设

论文假设 UAV 可以在任意两点之间直线飞行(deadhead),但现实中存在禁飞区、建筑物、高压线等障碍,无人机不能随意直线穿越。这使得 UAV 的飞行时间估算可能系统性偏低。

⚠ 不足四:仅仿真,无实机验证

所有实验均为基于 OpenStreetMap 数据的数值仿真,没有在真实机器人上验证。路网是真实的,但传感器噪声、定位误差、实际通信延迟等工程因素均被完全屏蔽。

⚠ 不足五:单 UGV 假设限制了应用范围

论文只考虑一辆 UGV,而真实救灾场景中往往需要多辆车辆协同行动(多辆救援车、多辆物资运输车)。多 UGV 情境下如何分配有限的 UAV 资源,是一个更复杂但更实用的问题,本文没有涉及。

八、横向视角:与前三篇论文的定位对比

至此,四篇论文形成了一个有趣的全景图:

论文 关注点 核心问题
CoPCS 大规模任务分配 多 UAV 访问所有任务点,UGV 提供充电支持
学习加速轨迹规划 精确轨迹生成 如何快速生成满足动力学约束的交接轨迹
GA3T 感知数据基础 为野外协同感知研究提供真实多模态数据集
DUCPP(本文) 不确定路网导航 道路可通行性未知时,如何用 UAV 探路引导 UGV

DUCPP 的独特性在于它关注的是信息不确定性下的路网导航 ,而不是轨迹精度或任务分配效率。它研究的是一个图论意义上更纯粹的决策问题:在知道什么、不知道什么的约束下,如何最优地行动

九、总结:一篇"土木工程师和算法工程师合写"的论文

DUCPP 解决的问题有一种朴实的工程气质------它不追求复杂的神经网络,不依赖大量训练数据,就是在一张图上想清楚:无人机应该先去探哪条边,才能让无人车少走弯路

双向策略的胜出也印证了一个古老的算法智慧:有时候最优雅的解法,是从两头同时出发

这篇论文真正的价值不在于方法有多复杂,而在于它把一个高度现实、高度紧迫的问题抽象清楚,并给出了可以直接实现、对比评估的多套方案。在灾害响应这个分秒必争的领域,这种扎实的工程导向研究,或许比很多精妙的理论工作更有落地可能。

十、代码实现

根据这篇论文 Dynamic UGV-UAV Cooperative Path Planning in Uncertain Environments 的描述,把它复现成一个可运行的 Python 仿真框架。

本质上是一个:

  • 图搜索环境建模(road network graph)

  • UGV状态机

  • UAV巡检状态机

  • 事件驱动动态重规划

  • 多种策略切换:

    • UGV-only
    • Kemeny
    • k-shortest
    • MPSP
    • Bidirectional(论文最优)
    • Multi-UAV Bidirectional

工程目录

text 复制代码
ducpp/
├── graph_env.py
├── vehicle.py
├── strategies.py
├── planner.py
├── experiments.py
└── main.py

安装依赖:

bash 复制代码
pip install networkx matplotlib numpy

1. graph_env.py

python 复制代码
import networkx as nx
import random
import math


class RoadGraph:
    def __init__(self):
        self.G = nx.Graph()
        self.edge_info = {}

    def add_edge(self, u, v, length, damage_prob=0.2):
        self.G.add_edge(u, v, weight=length)

        key = self.norm(u, v)

        self.edge_info[key] = {
            "length": length,
            "real_damaged": random.random() < damage_prob,
            "status": "unknown"
        }

    def norm(self, u, v):
        return tuple(sorted((u, v)))

    def inspect_edge(self, u, v):
        e = self.norm(u, v)

        if self.edge_info[e]["real_damaged"]:
            self.edge_info[e]["status"] = "damaged"

            if self.G.has_edge(*e):
                self.G.remove_edge(*e)

            return False

        self.edge_info[e]["status"] = "safe"
        return True

    def shortest_path(self, start, goal):
        try:
            return nx.shortest_path(
                self.G,
                start,
                goal,
                weight="weight"
            )
        except:
            return None

    def path_cost(self, path):
        if not path:
            return math.inf

        cost = 0
        for i in range(len(path) - 1):
            cost += self.G[path[i]][path[i+1]]["weight"]

        return cost

2. vehicle.py

python 复制代码
class UGV:
    def __init__(self, start, speed=20):
        self.start = start
        self.position = start
        self.speed = speed
        self.path = []

    def assign_path(self, path):
        self.path = path


class UAV:
    def __init__(self, start, speed=40):
        self.start = start
        self.position = start
        self.speed = speed
        self.inspect_target = None

    def assign_edge(self, edge):
        self.inspect_target = edge

3. strategies.py

UGV-only + Bidirectional + Multi-UAV

python 复制代码
class Strategy:
    def __init__(self, graph, ugv, goal):
        self.graph = graph
        self.ugv = ugv
        self.goal = goal

    def find_path(self):
        raise NotImplementedError


class UGVOnlyStrategy(Strategy):
    def find_path(self):
        path = self.graph.shortest_path(
            self.ugv.position,
            self.goal
        )

        if not path:
            return False

        self.ugv.assign_path(path)
        return True


class BidirectionalStrategy(Strategy):
    def __init__(self, graph, ugv, uav, goal):
        super().__init__(graph, ugv, goal)
        self.uav = uav

    def find_path(self):
        path = self.graph.shortest_path(
            self.ugv.position,
            self.goal
        )

        if not path:
            return False

        self.ugv.assign_path(path)

        for i in range(len(path)-1, 0, -1):
            edge = (path[i], path[i-1])

            if self.graph.edge_info[
                self.graph.norm(*edge)
            ]["status"] == "unknown":

                self.uav.assign_edge(edge)
                break

        return True


class MultiUAVBidirectionalStrategy(Strategy):
    def __init__(self, graph, ugv, uavs, goal):
        super().__init__(graph, ugv, goal)
        self.uavs = uavs

    def find_path(self):
        path = self.graph.shortest_path(
            self.ugv.position,
            self.goal
        )

        if not path:
            return False

        self.ugv.assign_path(path)

        assigned = []

        idx = len(path)-1

        for uav in self.uavs:
            while idx > 0:
                edge = (path[idx], path[idx-1])

                if edge not in assigned:
                    uav.assign_edge(edge)
                    assigned.append(edge)
                    idx -= 1
                    break

                idx -= 1

        return True

4. planner.py

论文 Algorithm 1

python 复制代码
import time


class DUCPPPlanner:
    def __init__(self, strategy):
        self.strategy = strategy
        self.total_travel_time = 0
        self.compute_time = 0

    def step(self):
        start = time.time()

        feasible = self.strategy.find_path()

        self.compute_time += time.time() - start

        if not feasible:
            return False

        if hasattr(self.strategy, "uav"):
            uav = self.strategy.uav

            if uav.inspect_target:
                self.strategy.graph.inspect_edge(
                    *uav.inspect_target
                )

        if hasattr(self.strategy, "uavs"):
            for uav in self.strategy.uavs:
                if uav.inspect_target:
                    self.strategy.graph.inspect_edge(
                        *uav.inspect_target
                    )

        ugv = self.strategy.ugv

        if len(ugv.path) > 1:
            nxt = ugv.path[1]

            safe = self.strategy.graph.inspect_edge(
                ugv.position,
                nxt
            )

            if safe:
                ugv.position = nxt

                self.total_travel_time += 1

        return ugv.position != self.strategy.goal

    def run(self):
        while self.step():
            pass

        return self.total_travel_time, self.compute_time

5. experiments.py

python 复制代码
import random
import matplotlib.pyplot as plt
import numpy as np

from graph_env import RoadGraph
from vehicle import UGV, UAV
from strategies import *
from planner import DUCPPPlanner


def random_graph(n=20):
    g = RoadGraph()

    for i in range(n):
        for j in range(i+1, n):
            if random.random() < 0.18:
                g.add_edge(
                    i, j,
                    random.randint(1, 10),
                    damage_prob=0.25
                )

    return g


def run_trial(strategy_type):

    g = random_graph()

    start = 0
    goal = 15

    ugv = UGV(start)

    if strategy_type == "ugv":
        strategy = UGVOnlyStrategy(g, ugv, goal)

    elif strategy_type == "bi":
        strategy = BidirectionalStrategy(
            g, ugv, UAV(10), goal
        )

    else:
        strategy = MultiUAVBidirectionalStrategy(
            g, ugv,
            [UAV(10), UAV(11), UAV(12)],
            goal
        )

    planner = DUCPPPlanner(strategy)

    return planner.run()


def benchmark():
    names = ["UGV-only", "Bidirectional", "3-UAV"]

    travel = []
    compute = []

    for s in ["ugv", "bi", "multi"]:
        t = []
        c = []

        for _ in range(50):
            tt, cc = run_trial(s)
            t.append(tt)
            c.append(cc)

        travel.append(np.mean(t))
        compute.append(np.mean(c))

    return names, travel, compute


def plot_results():
    names, travel, compute = benchmark()

    plt.figure(figsize=(12, 5))

    plt.subplot(121)
    plt.bar(names, travel)
    plt.title("Average UGV Travel Time")

    plt.subplot(122)
    plt.bar(names, compute)
    plt.title("Average Computation Time")

    plt.tight_layout()
    plt.show()

6. main.py

python 复制代码
from experiments import plot_results

plot_results()

运行

bash 复制代码
python main.py

和论文对应关系

论文模块 工程实现
Algorithm 1 DUCPPPlanner
Algorithm 2 step()
Algorithm 6 BidirectionalStrategy
Multiple UAV MultiUAVBidirectionalStrategy
Section IV Results benchmark()

进一步做科研复现

1. 接入真实地图

OpenStreetMapOSMnx

(1)OpenStreetMap(简称 OSM) 是一个全球性的开放协作地理数据库项目,旨在通过众包方式创建和维护免费的可编辑世界地图。其数据可被任何人自由使用、修改与分享,是众多地图应用和地理信息系统的基础数据来源。

链接:https://www.openstreetmap.org/

(2)OSMnx 是一个基于 Python 的开源库,用于从 OpenStreetMap 下载、建模、分析与可视化街道网络。它广泛应用于城市研究、交通规划、空间分析与可视化任务中,使研究者和开发者能轻松操作复杂的地理网络数据。

链接:https://osmnx.readthedocs.io/en/stable/

2. 替换为论文中的

  • k-shortest paths
  • MPSP
  • Kemeny centrality

3. 可视化机器人动态运动

用:

  • Matplotlib animation
  • 或者ROS RViz
相关推荐
是Yu欸6 小时前
AI跨模态鉴伪技术实测
人工智能·安全·ai作画·aigc·合合信息·ai-native·waic
声网6 小时前
Vercel 发布 AI SDK 5,引入语音 API;Ollama 新版本支持多模态交互 丨日报
人工智能
蓝速科技6 小时前
蓝速科技 AI 双屏翻译机:私模工艺与 AB 麦算法实测解析
人工智能·科技
声网6 小时前
阿里小号停止续费,10 月底下架 App;音频技术公司 Bragi 联合 OpenAI 为第三方耳机引入 GPT 语音助手丨日报
人工智能
人民新视野6 小时前
AI数字人公司厂商让数字人导览讲解对话成为智慧展厅展馆标配
人工智能
liguojun20256 小时前
智慧文体旅系统选哪家?豆米跳跳十年技术沉淀支持源码交付
java·大数据·人工智能·物联网·1024程序员节
超自然祈祷6 小时前
科技在发展,我们所做工作的范式也在变——Software1.0、2.0、3.0...
人工智能·科技
大强同学6 小时前
Kimi Code CLI
人工智能·agent·claude·skill·kimi code cli
深度研习笔记6 小时前
OpenCV工业视觉实战10|违规语音播报+弹窗告警+重复告警过滤,打造智能声光预警系统(项目加分必备)
人工智能·opencv·计算机视觉
湘美书院--湘美谈教育7 小时前
湘美书院主理人:AI世代武侠小说的基本特征与蕴意
大数据·人工智能·深度学习·机器学习·生活