From 31408c350042f3e384316fc9c77b7bb936d723c1 Mon Sep 17 00:00:00 2001 From: "JSD\\13999" <1399945104@qq.com> Date: Sat, 13 Jun 2026 16:13:10 +0800 Subject: [PATCH] =?UTF-8?q?docs(avoidance):=20=E6=94=B6=E6=9D=9F=20RVO2=20?= =?UTF-8?q?=E9=81=BF=E9=9A=9C=E5=8E=8B=E6=B5=8B=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FishROV/Docs/avoidance-core-comparison.html | 648 ++++++++++++++++++ FishROV/Docs/hrvo-core-principles.md | 239 +++++++ .../Docs/local-avoidance-benchmark-notes.md | 42 +- FishROV/Docs/rl-rvo-nav-core-principles.md | 230 +++++++ FishROV/Docs/rvo-py-mas-core-principles.md | 280 ++++++++ 5 files changed, 1437 insertions(+), 2 deletions(-) create mode 100644 FishROV/Docs/avoidance-core-comparison.html create mode 100644 FishROV/Docs/hrvo-core-principles.md create mode 100644 FishROV/Docs/rl-rvo-nav-core-principles.md create mode 100644 FishROV/Docs/rvo-py-mas-core-principles.md diff --git a/FishROV/Docs/avoidance-core-comparison.html b/FishROV/Docs/avoidance-core-comparison.html new file mode 100644 index 0000000..19354ae --- /dev/null +++ b/FishROV/Docs/avoidance-core-comparison.html @@ -0,0 +1,648 @@ + + + + + + RVO2 避障压测方案收束 + + + +
+
FishROV Avoidance Benchmark
+

RVO2 基准与自研版压测收束

+

+ 当前阶段先忽略复杂玩法状态,只压测局部避障算法在理想和极端条件下的表现。主线收束为两项:RVO2 原版作为成熟 ORCA 基准,基于 RVO2 思想的自研版作为项目可控方案。 +

+
+ +
+
+
+

压测结论

+

只测两条线就够

+

+ 如果当前目标是忽略实际玩法状态,只验证理想与极端条件下的局部避障性能,那么建议压测对象收束为: + RVO2 原版基于 RVO2 思想的自研版。RVO2 是稳定基准,自研版负责验证项目可控性、可调参空间和性能上限。 +

+
+ +
+

推荐压测口径

+
    +
  1. 理想情况:空旷水域、均匀分布、目标方向一致或轻微交叉,验证基础吞吐和稳定收敛。
  2. +
  3. 中等冲突:双向穿流、圆阵向心、随机目标切换,验证重叠率、抖动和换边稳定性。
  4. +
  5. 极端情况:高密度聚集、初始重叠、狭窄通道、所有 agent 争同一目标点,验证退化行为。
  6. +
  7. 规模阶梯:100、500、1000、3000、5000 agent,记录每帧耗时、最大耗时、重叠对、平均速度损失。
  8. +
  9. 移动端口径:固定竖屏 1080x1920,编辑器和百元机使用相同分辨率、数量档、场景和采样窗口。
  10. +
  11. 公平条件:相同半径、最大速度、timeStep、目标生成、积分方式、邻居查询范围和日志采样策略。
  12. +
+
+
+ +
+

日志与真实性要求

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
环境必须输出不要做推荐实现
Unity 编辑器算法、场景、数量、分辨率、平均 FPS、1% Low、模拟耗时、最大耗时、GC、XZ/3D 重叠对。不要每帧 `Debug.Log`,不要在热路径拼接字符串,不要每帧写文件。内存环形缓冲 + 固定间隔采样;单轮结束后一次性导出 CSV/JSON,并在 Console 只打印摘要。
百元机真机同一套指标,加设备型号、Unity 图形 API、目标帧率、分辨率 1080x1920、温度/降频观察备注。不要开详细 HUD、不要高频日志、不要连接调试器长期采样导致额外开销。Release/Development 分开测;真机默认静默聚合,测试结束或手动按钮导出日志文件。
性能公平性日志开销要对两个算法一致,最好能统计采样写入耗时。不要让某个算法额外输出调试明细,导致对比不公平。所有算法只写结构化数值样本,统一由 benchmark runner 收集和导出。
+
+
+ +
+
+

一句话判断

+

+ 如果当前阶段只做算法压测,RVO2 原版 + RVO2 思想自研版 就是最小有效对照组。 + 其他方案暂时不必进入压测主线,可以作为解释来源或后续扩展参考。 +

+
+ +
+

共同点

+
    +
  • 大多数方案都需要上层提供目标或期望速度,然后再做局部修正。
  • +
  • 核心输入都离不开位置、速度、半径、邻居范围和预测时间。
  • +
  • 都在权衡两个目标:尽量接近期望运动,同时减少未来碰撞风险。
  • +
  • 除 NavMesh 外,大多数方案都不负责全局路径,不理解死胡同、任务顺序和长期收益。
  • +
  • 在 FishROV 的 3D/2.5D 场景里,多数方案仍需要明确如何处理 XZ 投影、高度层和真实体积冲突。
  • +
+
+
+ +
+

核心矩阵

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
方案核心抽象最终如何选速度安全性来源最擅长主要风险FishROV 定位
RVO2 / ORCA速度空间半平面约束
把每个邻居变成 ORCA 线性约束。
在所有安全半平面内,求最接近期望速度的新速度。显式几何约束和低维优化,理论性最强。大规模多动态 agent 的实时局部避障。不做全局规划,2D 投影,参数不当会保守、停滞或碰撞。最适合作为局部避障工程基准和对照组。
HRVO速度空间混合 VO/RVO
把 VO 与 RVO 的几何边界混合。
排除危险速度,再选择接近期望速度且更稳定的速度。速度障碍几何,加上减少 reciprocal 振荡的边界设计。对称对冲、互相避让时减少左右横跳。仍是局部 2D 方法,不处理地图和动力学约束。适合作为处理振荡问题的设计参考。
RVO_Py_MAS速度空间采样过滤
把动态体和静态障碍都转成速度禁区。
采样候选速度,先过滤禁区,有安全速度就选最接近期望速度的;没有安全速度则选折中。禁区过滤加碰撞时间折中,不是严格 ORCA 求解。学习 RVO 建模方式,快速改造原型。没有空间索引时规模变贵,采样可能错过好速度。适合作为可读的 RVO 原理参考,不建议直接当大规模生产方案。
采样避障学习版候选速度评分函数
候选速度由期望速度、偏转、减速、停止等组成。
对每个候选速度计算目标偏差、平滑、预测碰撞、当前重叠、边界等惩罚,选最低分。启发式风险函数和权重调参,不保证无碰撞。项目内自研、调参、验证新评分项。权重依赖场景,高密度可能局部最优或卡住。最适合作为 FishROV 自研避障算法的实验骨架。
rl_rvo_nav学习策略RVO 先验
把 VO/RVO 风险编码进状态和奖励。
PPO actor 根据自身状态和 VO/RVO 序列输出速度增量。训练经验、RVO 区域奖励、预计碰撞时间塑形。复杂多机器人场景下学习更灵活的风险权衡。训练成本高,泛化依赖仿真覆盖,工程可控性较弱。建议先吸收风险表达和 reward/score 思想,不急着引入完整 RL 链路。
Unity NavMeshAgent导航网格路径跟随
先理解哪里能走,再沿路径局部避让。
在 NavMesh 上规划路径,沿拐点移动,同时使用内置局部避让。全局可达性、路径搜索、内置工程避让。静态地图、走廊、房间、地形导航。局部避障不是核心强项,高密度动态体易抖,主要是平面系统。适合作为全局路径层或工程对照,不适合作为鱼群局部避障核心。
+
+
+ +
+

真正拉开差距的六个轴

+
+
+

1. 位置空间还是速度空间

+

RVO2、HRVO、RVO_Py_MAS、rl_rvo_nav 都把问题转成“哪些速度会导致未来碰撞”。NavMesh 主要先回答“哪里能走”。采样学习版虽然是评分,但最关键的预测碰撞项也已经进入速度空间。

+
+
+

2. 约束、过滤还是惩罚

+

ORCA 是约束求解,危险速度直接被半平面排除。RVO_Py_MAS 是采样后过滤禁区。采样学习版是给风险加惩罚,危险速度未必完全禁止。RL 是把风险变成训练信号。

+
+
+

3. 谁承担避让责任

+

VO 偏“我躲别人”;RVO/ORCA 假设双方共同承担;HRVO 在 reciprocal 基础上减少来回换边。NavMesh 用优先级处理谁让路。采样版需要靠评分项或通行偏置来塑造行为。

+
+
+

4. 是否理解地图

+

NavMesh 有全局可达性和路径图。其他方案基本只处理局部邻居,不知道死胡同、洞穴、任务顺序和远期收益。因此 FishROV 最可能需要“全局/中层路径 + 局部避障 + 运动控制”的分层结构。

+
+
+

5. 可解释性和可改性

+

RVO2 理论清晰但实现复杂。采样学习版最容易改权重和新增评分项。RVO_Py_MAS最适合读懂速度障碍。RL 灵活但可解释性和复现实验成本更高。NavMesh 是工程黑盒较多的成熟系统。

+
+
+

6. 2D 与 3D 的边界

+

这些方案多数原生是 2D 或平面导航。FishROV 里如果只看 XZ,会把不同高度层的对象误判为冲突,也可能漏掉真实 3D 体积风险。核心决策必须明确水平避障、高度分层和体积碰撞的关系。

+
+
+
+ +
+

工程选择倾向

+
+
理论安全约束
+
+
RVO2 / ORCA
+
HRVO
+
采样 / RL
+
+
+
+
可改可调
+
+
采样学习版
+
RVO_Py_MAS
+
NavMesh / RVO2
+
+
+
+
全局路径能力
+
+
NavMeshAgent
+
RVO 系列
+
采样 / RL
+
+
+
+ +
+

推荐读法

+
+
+

先压测 RVO2

+

RVO2 / ORCA 当成标准基线,确认理想、拥挤、对冲、初始重叠等场景下的耗时和重叠率。

+
+
+

再压测自研版

+

自研版可以先吸收 RVO2 的速度空间思想,但保留可调评分、鱼群权重和性能优化入口。

+
+
+

暂缓其他方案

+

NavMesh、HRVO、RL-RVO 暂时不用进主压测。先把两条主线测准,再决定是否补防振荡或全局可达性。

+
+
+
+ +
+

依据文档:rvo2-core-principles.md、unity-navmesh-core-principles.md、sampling-local-avoidance-core-principles.md、hrvo-core-principles.md、rvo-py-mas-core-principles.md、rl-rvo-nav-core-principles.md。

+
+
+ + diff --git a/FishROV/Docs/hrvo-core-principles.md b/FishROV/Docs/hrvo-core-principles.md new file mode 100644 index 0000000..19939be --- /dev/null +++ b/FishROV/Docs/hrvo-core-principles.md @@ -0,0 +1,239 @@ +# HRVO 核心原理 + +## 一句话结论 + +HRVO 的核心是 **在速度空间里排除未来会发生碰撞的速度,然后选择一个尽量接近期望速度、同时更不容易产生左右振荡的新速度**。 + +它不是全局寻路算法,也不是推进器控制器,而是一个去中心化的局部避障算法。每个 agent 只根据自己感知到的邻居位置和速度独立决策,不需要中心调度,也不需要 agent 之间通信。 + +仓库地址: + +```text +https://github.com/snape/HRVO +``` + +## 要解决的问题 + +多 agent 避障最麻烦的不是单个障碍物,而是 **大家都会动,并且大家都会试图避让**。 + +如果用简单 steering,常见逻辑是: + +```text +朝目标走 +靠近别人就加一个排斥力 +最后合成速度 +``` + +这种方式容易出现几个问题: + +- 只看当前距离,不一定能判断未来是否会撞上。 +- 多个 agent 同时避让时,可能互相把对方推乱。 +- 对称场景下容易左右摇摆。 +- 高密度场景里,排斥力叠加后速度可能非常不稳定。 + +HRVO 换了一个视角:不直接在位置空间里把 agent 推开,而是在速度空间里判断: + +```text +如果我现在选择这个速度, +按照邻居的当前位置和速度预测, +未来一小段时间内会不会撞上? +``` + +会撞的速度,就是不能选的速度。 + +## Velocity Obstacle + +Velocity Obstacle,简称 VO,表示速度空间中的危险区域。 + +假设有两个 agent:A 和 B。 + +- A 的位置是 `pA`,速度是 `vA`,半径是 `rA`。 +- B 的位置是 `pB`,速度是 `vB`,半径是 `rB`。 +- 如果未来某个时间,两者中心距离小于 `rA + rB`,就会发生碰撞。 + +对 A 来说,可以把 B 膨胀成半径 `rA + rB` 的圆。然后在速度空间中构造一片区域: + +```text +如果 A 选择这片区域里的速度, +并且 B 继续保持当前速度, +A 未来会撞到 B。 +``` + +这片速度区域就是 B 对 A 产生的 Velocity Obstacle。 + +直观理解: + +```text +位置空间:哪里有障碍? +速度空间:哪些速度会导致未来撞上障碍? +``` + +VO 的价值在于,它把动态碰撞预测变成了当前帧的速度选择问题。 + +## RVO:双方共同承担避让 + +普通 VO 假设“别人保持当前速度,我来躲”。这在动态 agent 群里会偏保守,因为实际上对方也会躲。 + +RVO 的思想是 reciprocal: + +```text +A 和 B 都是主动体。 +如果两者当前速度组合会导致碰撞, +不应该让 A 独自承担全部避让修正。 +双方各承担一部分速度修正。 +``` + +这样 agent 的行为会更自然,尤其适合: + +- 机器人群; +- 人群模拟; +- 鱼群或艇群; +- 多个同等级 NPC 的局部避让。 + +## HRVO:减少 reciprocal 避让振荡 + +RVO 虽然比 VO 更对称,但在某些对称场景中仍然可能出现振荡。 + +典型例子: + +```text +A 和 B 正面对冲 +这一帧双方都觉得向左让比较好 +下一帧相对状态变化后,双方又都觉得向右让比较好 +然后反复左右切换 +``` + +HRVO 的关键改进就是 Hybrid: + +```text +它不是完全使用 VO,也不是完全使用 RVO, +而是把两者的几何边界混合起来, +构造一个更偏向稳定避让侧的速度障碍。 +``` + +直观说,HRVO 会让速度障碍的顶点和边界选择更偏向“别来回改主意”,从而减少互相避让时的左右横跳。 + +所以 HRVO 关注的不只是无碰撞,还包括: + +```text +collision-free +oscillation-free +decentralized +``` + +也就是无碰撞、少振荡、去中心化。 + +## 每帧流程 + +HRVO 每帧大致做这些事: + +1. 更新每个 agent 的当前位置和当前速度。 +2. 为每个 agent 设置期望速度 `preferredVelocity`。 +3. 查找附近邻居。 +4. 对每个邻居构造一个 HRVO 速度障碍。 +5. 在可选速度中寻找一个不落入危险区域、且最接近期望速度的新速度。 +6. 用新速度推进 agent。 + +可以理解成: + +```text +目标方向 + -> 期望速度 + -> 邻居预测 + -> 构造速度禁区 + -> 选择安全速度 + -> 推进位置 +``` + +## 和 VO / RVO / ORCA 的区别 + +| 方法 | 核心假设 | 主要特点 | +| --- | --- | --- | +| VO | 我躲别人,别人保持当前速度 | 简单直接,但对动态群体偏保守 | +| RVO | 双方都会避让,各承担一部分修正 | 更适合多 agent,但对称场景可能振荡 | +| HRVO | 混合 VO 和 RVO 的速度障碍 | 在 reciprocal 基础上减少左右振荡 | +| ORCA | 把避障转成半平面约束和优化问题 | 工程上更常用,求解形式更规整 | + +HRVO 可以看作 RVO 家族中的一个改进版本,重点是处理 reciprocal collision avoidance 中的振荡问题。 + +## 关键参数 + +HRVO 这类算法通常会关心这些参数: + +- `radius`:agent 半径,决定碰撞距离。 +- `neighborDist`:多远范围内的 agent 会被当作邻居。 +- `maxNeighbors`:最多考虑多少邻居。 +- `timeHorizon`:向未来预测多长时间内的碰撞。 +- `maxSpeed`:最大速度。 +- `timeStep`:仿真步长。 + +参数影响很直接: + +- `neighborDist` 太小:反应太晚,容易贴脸避让。 +- `neighborDist` 太大:邻居过多,性能下降,也可能过度保守。 +- `timeHorizon` 太短:只处理眼前风险。 +- `timeHorizon` 太长:提前避让过多,路径可能绕或慢。 +- `maxNeighbors` 太低:高密度时可能漏掉重要邻居。 + +## 优点 + +- 去中心化,不需要统一调度所有 agent。 +- 对多动态 agent 场景更自然。 +- 使用速度空间建模,可解释性比纯排斥力强。 +- 相比普通 RVO,更重视减少对称避让中的振荡。 +- 适合实时局部避障。 + +## 局限 + +- 它主要是二维平面局部避障算法。 +- 不负责全局路径规划。 +- 不理解地图语义、死胡同、长期收益。 +- 对强动力学约束系统需要额外适配。 +- 高密度或狭窄通道中仍可能出现局部最优、停滞或拥堵。 +- 如果 agent 初始已经严重重叠,算法需要时间把重叠解开。 + +## 放到 FishROV 中的定位 + +在 FishROV 里,HRVO 更适合作为一层局部避障参考,而不是完整运动方案。 + +建议定位: + +```text +全局目标 / 路径 + -> 生成期望速度 + -> HRVO 局部避障修正速度 + -> FishROV 自身运动控制 / 刚体控制 / 推进器控制 +``` + +也就是说,HRVO 输出的是“当前更安全的速度建议”,不是最终控制指令。 + +如果用于 ROV 或鱼群 benchmark,需要特别注意: + +- 如果当前运动是 3D,HRVO 原生二维模型需要投影到 XZ 平面,或扩展为 3D 近似。 +- 如果存在水流、惯性、最大转向角、加速度限制,需要在 HRVO 输出之后再做动力学约束。 +- 如果有地形、洞穴、障碍物、任务点顺序,仍然需要全局或中层规划。 +- 如果 agent 高度层不同,不能只看 XZ 重叠,否则会把视觉上错层的对象也当成冲突。 + +## 对自研避障算法的启发 + +HRVO 最值得吸收的不是具体代码,而是这三个思想: + +```text +1. 在速度空间里判断未来碰撞,而不是只看当前距离。 +2. 假设其他动态体也会避让,而不是全部由自己承担。 +3. 对称避让时要显式处理振荡,不然会左右横跳。 +``` + +如果后续继续做 FishROV 自研局部避障,可以把 HRVO 作为参考方向: + +- 用预测碰撞时间替代单纯距离惩罚。 +- 把候选速度分成安全区、危险区和高风险区。 +- 给 reciprocal 避让加入稳定侧偏好,减少频繁换边。 +- 把“接近期望速度”和“避碰安全”放进同一个评分或约束求解里。 +- 在 3D 场景中明确区分水平面冲突和真实体积冲突。 + +## 参考 + +- HRVO 仓库:https://github.com/snape/HRVO +- HRVO 项目页:https://gamma.cs.unc.edu/HRVO/ +- Velocity Obstacle 术语说明:https://en.wikipedia.org/wiki/Velocity_obstacle diff --git a/FishROV/Docs/local-avoidance-benchmark-notes.md b/FishROV/Docs/local-avoidance-benchmark-notes.md index 4566912..d3cffe5 100644 --- a/FishROV/Docs/local-avoidance-benchmark-notes.md +++ b/FishROV/Docs/local-avoidance-benchmark-notes.md @@ -2,7 +2,12 @@ ## 目标 -这个 Unity 工程用于横向压测本地避障方案。不同方案之间唯一应该变化的变量,是 `AvoidanceFrameworkKind` 选择后由 `AvoidanceAdapterRegistry` 创建的 adapter。 +这个 Unity 工程用于压测本地避障方案。当前阶段先收束到两条主线: + +- `Rvo2Adapter`:成熟 RVO2 / ORCA 基准。 +- 项目自研 RVO2 思想版本:用于验证可控性、可调参空间和性能上限。 + +其他方案可以保留为参考或历史对照,但不进入当前主压测结论。不同方案之间唯一应该变化的变量,是 `AvoidanceFrameworkKind` 选择后由 `AvoidanceAdapterRegistry` 创建的 adapter。 ## 共享运行入口 @@ -46,7 +51,40 @@ adapter 可以给运行时创建的对象追加框架自己的组件,但不应 `NoAvoidanceAdapter` 是对照基线:只按期望速度移动,不做避障。 -A* RVO、RVO2、Unity NavMesh、采样避障学习版都通过同一个调试面板选择,用同一套场景、数量、相机和指标进行对比。 +当前压测结论主线只比较 RVO2 原版和基于 RVO2 思想的自研版本。A* RVO、Unity NavMesh、采样避障学习版可以继续保留在调试面板里,但当前不作为主结论对象。 + +## 当前压测口径 + +- 分辨率:标准移动端竖屏 `1080x1920`。 +- 环境:先在 Unity 编辑器下跑同一套场景,再到百元机真机复测。 +- 场景:理想空旷、双向穿流、圆阵向心、高密度聚集、初始重叠、狭窄通道、单目标争抢。 +- 数量档:建议至少覆盖 `100 / 500 / 1000 / 3000 / 5000`。 +- 指标:平均 FPS、1% Low FPS、模拟耗时、最大模拟耗时、GC 分配、XZ 平面重叠对数、3D 空间重叠对数、最近清空间距、平均速度损失。 +- 公平条件:半径、最大速度、`timeStep`、目标生成、积分方式、邻居范围、日志采样策略必须一致。 + +## 日志策略 + +编辑器和百元机都需要日志,但日志不能拖慢性能测试。 + +- 不要每帧 `Debug.Log`。 +- 不要在热路径里拼接字符串。 +- 不要每帧写文件。 +- 不要让某个 adapter 单独输出额外明细,导致对比不公平。 +- 建议只在内存中记录结构化数值样本。 +- 建议固定间隔采样,例如每 `0.5s` 或每 `30` 帧聚合一次。 +- 建议使用环形缓冲或预分配数组,避免压测中产生 GC。 +- 单轮结束后一次性导出 CSV/JSON。 +- Console 只打印一行摘要,例如算法、场景、数量、平均 FPS、1% Low、平均模拟耗时、最大耗时、重叠对峰值。 + +百元机真机日志建议额外记录: + +- 设备型号。 +- 目标帧率。 +- 实际分辨率是否为 `1080x1920`。 +- Unity 图形 API。 +- 是否 Development Build。 +- 是否连接调试器。 +- 是否出现明显发热、降频或后台干扰。 ## A* Pathfinding Project Pro RVO Adapter diff --git a/FishROV/Docs/rl-rvo-nav-core-principles.md b/FishROV/Docs/rl-rvo-nav-core-principles.md new file mode 100644 index 0000000..0c59994 --- /dev/null +++ b/FishROV/Docs/rl-rvo-nav-core-principles.md @@ -0,0 +1,230 @@ +# rl_rvo_nav 核心原理说明 + +资料来源: + +- GitHub 仓库:https://github.com/hanruihua/rl_rvo_nav +- 论文:Reinforcement Learned Distributed Multi-Robot Navigation with Reciprocal Velocity Obstacle Shaped Rewards +- arXiv 页面:https://arxiv.org/abs/2203.10229 + +## 一句话结论 + +`rl_rvo_nav` 的核心不是纯强化学习避障,也不是传统 RVO/ORCA 求解器,而是把 **RVO/VO 几何避障先验** 编码进强化学习的状态表示和奖励函数中,让 PPO 训练出的策略在多机器人局部避障中更安全、更高效、更不保守。 + +可以理解为: + +> RVO 负责告诉策略“哪些速度区域有碰撞风险”,强化学习负责学“在这些风险结构下,当前该怎么选一个更好的速度增量”。 + +## 背景问题 + +多机器人导航常见有两类方案: + +- 中心化调度:全局规划能力强,但机器人数量增加后计算和通信压力上升。 +- 分布式避障:每个机器人独立决策,扩展性好,但只能依靠局部观测,容易出现碰撞、震荡、过度保守或互相等待。 + +传统 VO/RVO/ORCA 方法会在速度空间中构造不可选速度区域,从而实时选择避障速度。它们计算高效、可解释,但在复杂场景中可能保守,对感知误差、非完整约束和长期收益的处理也有限。 + +纯深度强化学习方法可以通过大量仿真经验学到更激进、更灵活的策略,但如果直接输入位置、速度、距离等原始状态,网络需要自己学会推导碰撞几何关系,样本效率和可控性都不理想。 + +`rl_rvo_nav` 的设计目标就是结合两者: + +- 用 RVO/VO 给强化学习提供结构化避障知识。 +- 用 DRL 学出比手写几何规则更灵活的局部控制策略。 + +## 核心模块 + +### 1. 分布式多机器人决策 + +每个机器人独立运行同一个策略,不依赖中心控制器,也不依赖机器人之间的通信。 + +机器人只使用自身状态和局部感知范围内的其他机器人、障碍物信息进行决策。 + +自身状态通常包括: + +- 当前速度 +- 当前朝向 +- 期望速度 +- 用于避障的虚拟半径 + +周围环境状态包括: + +- 动态机器人产生的 RVO 向量 +- 静态障碍物产生的 VO 向量 +- 相对距离 +- 预计碰撞时间 + +### 2. 用 RVO/VO 表示碰撞风险 + +传统 RL 避障常把邻居机器人表示成位置、速度、半径等数据,例如: + +```text +other_position, other_velocity, other_radius +``` + +`rl_rvo_nav` 更进一步,把这些信息转换成速度空间中的 VO/RVO 表示。 + +VO 表示: + +- 如果自身选择某些速度,就会在未来一段时间内撞到障碍物。 +- 这些危险速度构成一个速度空间区域。 + +RVO 表示: + +- 对动态机器人,不只假设“我避让它”,而是假设双方都会承担一部分避让责任。 +- 这让策略更容易学到互惠避障行为,减少单方过度避让或互相卡住。 + +因此,网络输入不是单纯的几何坐标,而是更接近“碰撞约束”的状态。 + +这也是该方案最重要的思想:**把避障问题从物理空间状态学习,转成速度空间风险学习。** + +### 3. BiGRU 处理可变数量邻居 + +周围机器人和障碍物数量是不固定的。普通 MLP 需要固定长度输入,不适合直接处理可变数量的邻居。 + +该方案把周围对象的 VO/RVO 信息组织成序列,再用 RNN 模块提取特征。 + +论文强调使用 bidirectional GRU,也就是 BiGRU。仓库代码中的 `policy_rnn_ac.py` 里也能看到 `GRU`、`LSTM`、`biGRU` 模式。 + +结构大致是: + +```text +自身状态 + + +周围对象 VO/RVO 序列 + -> GRU/BiGRU + -> 固定维度环境特征 + -> Actor 输出动作分布 + -> Critic 输出状态价值 +``` + +BiGRU 的作用是: + +- 能处理数量变化的邻居。 +- 不只偏向序列末尾对象。 +- 在较低计算成本下提取局部交互特征。 + +### 4. 动作输出是速度增量 + +很多 RL 避障方法直接输出最终控制速度。 + +`rl_rvo_nav` 输出的是当前速度的增量,也就是 velocity increment/change rate。 + +这样做的好处: + +- 控制更平滑。 +- 不容易出现速度突变。 +- 更接近差速机器人实际控制需求。 + +最终速度再被分解成差速机器人的线速度和角速度。 + +### 5. 奖励函数由 RVO 区域和预计碰撞时间塑形 + +该方案的奖励函数不是简单距离奖励。 + +传统距离奖励大致是: + +- 离目标更近,奖励。 +- 离障碍更近,惩罚。 +- 碰撞,强惩罚。 + +但 `rl_rvo_nav` 的输入本身是 VO/RVO 表示,不直接以原始位置距离为核心。因此它设计了基于 RVO/VO 区域的奖励。 + +奖励重点判断: + +- 当前选择的速度是否落入 RVO/VO 危险区域。 +- 当前速度与期望速度的差距。 +- 按当前运动趋势,预计多久会发生碰撞。 + +预计碰撞时间比单纯距离更有信息量,因为它同时考虑了距离和相对速度。 + +例如: + +- 距离近但相对远离,风险不一定高。 +- 距离远但高速相向,风险可能很高。 + +所以该方案用 expected collision time 来衡量碰撞风险,使策略在拥挤环境里能更合理地权衡安全和效率。 + +## 训练方式 + +仓库使用 PPO 训练 actor-critic 策略。 + +训练流程大致如下: + +1. 在仿真环境中让多个机器人运行当前策略。 +2. 收集每个机器人的 observation、action、reward。 +3. 使用 GAE 计算优势。 +4. 用 PPO 更新 actor 和 critic。 +5. 在更复杂机器人数量和场景中继续训练。 + +README 中给出的训练阶段是: + +- 第一阶段:4 个机器人 circle 场景。 +- 第二阶段:加载已有模型,在 10 个机器人 circle 场景继续训练。 + +测试场景包括: + +- circle scenario +- random scenario + +## 与传统 RVO/ORCA 的区别 + +| 维度 | 传统 RVO/ORCA | rl_rvo_nav | +| --- | --- | --- | +| 决策方式 | 手写几何规则或优化求解 | 神经网络策略 | +| 避障知识 | 显式速度空间约束 | 作为状态和奖励先验 | +| 输出 | 当前最优避障速度 | 速度增量 | +| 优点 | 可解释、稳定、实时 | 更灵活,可从经验中学习效率和风险权衡 | +| 风险 | 可能保守 | 依赖训练覆盖和仿真质量 | + +## 与纯强化学习避障的区别 + +| 维度 | 纯 DRL 避障 | rl_rvo_nav | +| --- | --- | --- | +| 输入 | 位置、速度、距离、传感器数据等 | VO/RVO 风险向量 | +| 学习难度 | 网络需自行推导碰撞几何 | 几何风险已经结构化 | +| 奖励 | 常基于距离和碰撞结果 | 基于 RVO 区域和预计碰撞时间 | +| 可解释性 | 较弱 | 更容易解释为速度空间风险规避 | + +## 对 FishROV 的启发 + +如果把这个方案借鉴到 FishROV 或水下 ROV 局部避障中,最值得吸收的不是直接照搬 PPO 训练,而是以下思想: + +1. **把避障风险表达在速度空间中** + + 不只判断“障碍在哪里”,而是判断“当前可选速度里哪些会导致未来碰撞”。 + +2. **把规则避障和学习策略分层** + + 几何规则可以生成风险特征,学习策略负责在风险、目标方向、速度平滑性之间做权衡。 + +3. **优先考虑可解释的 reward/score** + + 即使不用 RL,也可以把 RVO 区域、预计碰撞时间、目标速度差异组合成局部避障评分函数。 + +4. **对动态障碍比静态障碍更有价值** + + 如果 FishROV 主要面对静态地形或固定障碍,传统 NavMesh、A*、局部 steering 可能更直接。 + + 如果未来要处理鱼群、其他 ROV、移动机械臂、动态水流漂浮物等,RVO/RL-RVO 的价值会明显上升。 + +## 局限和注意点 + +该方案也有明显门槛: + +- 需要高质量仿真环境。 +- 策略泛化依赖训练场景覆盖。 +- PPO 训练成本高于传统局部避障。 +- 真实机器人部署需要考虑感知误差、控制延迟、水动力扰动等 sim-to-real 问题。 +- 对游戏或仿真项目来说,直接使用 RL 模型未必划算,抽取其 RVO 风险建模思想可能更实用。 + +## 简短评价 + +`rl_rvo_nav` 最核心的价值是提出了一种很清楚的混合范式: + +```text +传统几何避障知识 + -> 结构化状态表示 + -> RVO/碰撞时间塑形奖励 + -> PPO 学习连续局部控制策略 +``` + +它适合研究或高复杂度多机器人动态避障。如果当前目标是工程落地,建议优先把它当作“设计参考”:吸收 VO/RVO 风险表达和 expected collision time 评分,而不是第一步就引入完整 RL 训练链路。 diff --git a/FishROV/Docs/rvo-py-mas-core-principles.md b/FishROV/Docs/rvo-py-mas-core-principles.md new file mode 100644 index 0000000..7ca25ce --- /dev/null +++ b/FishROV/Docs/rvo-py-mas-core-principles.md @@ -0,0 +1,280 @@ +# RVO_Py_MAS 核心原理 + +## 一句话结论 + +`RVO_Py_MAS` 的核心是 **在速度空间里排除未来会碰撞的速度,然后选择一个最接近期望速度的安全速度**。 + +它不是全局寻路系统,也不负责生成完整路径。它更像一个局部避障控制器:上层系统先给每个 agent 一个期望速度,RVO 再根据周围动态 agent 和静态障碍,把这个速度修正成更安全的实际速度。 + +典型接入方式是: + +```text +目标/任务控制器 + -> 计算期望速度 V_desired + -> RVO_Py_MAS 根据邻居和障碍修正速度 + -> 输出实际速度 V + -> 推进位置 +``` + +## 它要解决的问题 + +普通 steering 或分离力算法通常在位置空间工作: + +```text +离目标近一点 +离邻居远一点 +离障碍远一点 +最后把多个力合成一个速度 +``` + +这类方法简单,但容易出现几个问题: + +- 只看当前距离,不一定能判断未来是否会撞上。 +- 多个 agent 同时互相躲避时,可能左右摇摆。 +- 高密度场景下,分离力叠加后速度容易变乱。 +- 很难回答“这个速度在未来一小段时间内是否安全”。 + +RVO 的视角不同。它不直接问“我现在离别人多近”,而是问: + +```text +如果我选择这个速度, +在未来一段时间内会不会撞到别人? +``` + +## Velocity Obstacle + +对两个 agent A 和 B: + +- A 的位置是 `pA`,速度是 `vA`,半径是 `rA`。 +- B 的位置是 `pB`,速度是 `vB`,半径是 `rB`。 +- 如果未来某个时间点,两者中心距离小于 `rA + rB`,就会发生碰撞。 + +Velocity Obstacle 的意思是: + +```text +对 A 来说,有一片速度区域是危险的。 +如果 A 选择这片区域内的速度, +并且 B 按当前趋势运动, +A 未来就可能撞到 B。 +``` + +这片危险区域可以理解成速度空间里的一个锥形区域。锥的方向由 A 指向 B 的相对位置决定,锥的张角由双方半径和距离决定。 + +## RVO:双方共同承担避让 + +普通 VO 假设“对方保持原样,我单方面避让”。如果所有 agent 都这么算,就容易过度避让或振荡。 + +RVO 的关键变化是: + +```text +A 和 B 都是主动体。 +如果未来可能碰撞,不应该只让 A 负责全部避让。 +双方都假设对方也会做类似避让,因此各自承担一部分速度修正。 +``` + +在 `RVO_Py_MAS` 代码里,RVO 版本的速度障碍平移点使用了双方当前速度的平均项: + +```python +transl_vB_vA = [ + pA[0] + 0.5 * (vB[0] + vA[0]), + pA[1] + 0.5 * (vB[1] + vA[1]), +] +``` + +这就是 reciprocal 的工程化表达:不是单边躲避,而是假设双方都会动一点。 + +## 每个 agent 的计算流程 + +`RVO_update` 对每个 agent 做下面几步: + +1. 读取当前 agent 的位置 `pA` 和当前速度 `vA`。 +2. 遍历其他 agent。 +3. 为每个邻居构造一个 RVO 速度障碍。 +4. 遍历静态圆形障碍,也构造速度障碍。 +5. 调用 `intersect`,从候选速度里选择最合适的速度。 +6. 把结果写回输出速度列表。 + +可以简化成: + +```text +对每条鱼: + 收集周围会影响它的动态体和静态障碍 + 把这些对象都转成速度空间中的禁区 + 找一个不在禁区里、又最接近期望速度的速度 +``` + +## 动态 agent 如何形成禁区 + +对每个邻居 B,代码会计算: + +- `dist_BA`:A 和 B 的距离。 +- `theta_BA`:A 指向 B 的方向角。 +- `theta_BAort`:碰撞锥的半角。 +- `bound_left` / `bound_right`:碰撞锥左右边界。 + +然后把这个速度障碍存成: + +```python +RVO_BA = [ + transl_vB_vA, + bound_left, + bound_right, + dist_BA, + 2 * ROB_RAD, +] +``` + +其中 `2 * ROB_RAD` 表示两个相同半径 agent 的安全距离。代码里还给机器人半径额外加了 `0.1`,相当于保守安全边距。 + +## 静态障碍如何处理 + +静态障碍被当成速度为 0 的对象: + +```python +vB = [0, 0] +``` + +圆形障碍直接用自身半径加 agent 半径形成安全距离。代码里还有一个 `OVER_APPROX_C2S = 1.5`,用于把某些障碍做更保守的圆形近似。 + +所以动态 agent 和静态障碍最终都被转成同一种东西: + +```text +速度空间里的危险区域 +``` + +这让算法主体可以统一处理。 + +## 候选速度选择 + +`intersect` 函数不是做严格的数学优化,而是在速度空间里采样候选速度: + +```python +for theta in numpy.arange(0, 2 * PI, 0.1): + for rad in numpy.arange(0.02, norm_v + 0.02, norm_v / 5.0): + new_v = [rad * cos(theta), rad * sin(theta)] +``` + +也就是: + +```text +按不同方向 theta 采样 +按不同速度大小 rad 采样 +组合成一批候选速度 +``` + +每个候选速度都会拿去检查:它是否落在任意一个 RVO 禁区里。 + +- 没落入禁区:放入 `suitable_V`。 +- 落入禁区:放入 `unsuitable_V`。 + +## 如果有安全速度 + +如果存在 `suitable_V`,算法选一个最接近期望速度 `vA` 的速度: + +```python +vA_post = min(suitable_V, key=lambda v: distance(v, vA)) +``` + +这体现了 README 里说的“minimal modification of desired velocity”: + +```text +能不改就不改。 +必须避让时,也尽量少改。 +``` + +## 如果没有安全速度 + +高密度或被包围时,可能没有任何候选速度完全安全。 + +这时算法会从 `unsuitable_V` 里选一个折中速度。它会估计每个不安全速度的碰撞时间 `tc`,然后用下面的代价选择: + +```python +(WT / tc) + distance(v, vA) +``` + +含义是: + +```text +尽量晚碰撞 +同时尽量接近期望速度 +``` + +这不是严格安全保证,而是“没有好选择时选一个相对不坏的选择”。 + +## VO / RVO / HRVO 的区别 + +这个仓库的代码里保留了三种思路的切换痕迹: + +| 方法 | 核心假设 | 工程表现 | +| --- | --- | --- | +| VO | 对方保持当前速度,我单方避让 | 简单,但多主动体容易过度避让 | +| RVO | 双方都会避让,各承担一部分修正 | 更适合多 agent 对等场景 | +| HRVO | 混合 VO 和 RVO,减少振荡和死锁 | 理论上更稳,但实现略复杂 | + +当前代码默认使用 RVO。普通 VO 和 HRVO 的部分在代码里以注释形式保留。 + +## 优点 + +- 思路直观,代码量小,适合学习和改造。 +- 不需要复杂全局地图,只依赖局部位置、速度、半径。 +- 上层控制目标可以保持独立,只需要提供期望速度。 +- 对多 agent 场景比单纯分离力更有“未来碰撞预测”意识。 +- 动态 agent 和静态障碍可以统一成速度空间约束。 + +## 局限 + +- 这是局部避障,不是全局寻路。 +- 候选速度靠采样,可能错过真正更优的速度。 +- 高密度场景可能没有完全安全速度,只能选折中。 +- 代码没有空间索引,agent 数量大时两两遍历会变贵。 +- 它不是 ORCA/RVO2 那种半平面约束加线性规划求解。 +- 参数、步长、最大速度不合适时仍可能碰撞或卡住。 + +## 和 RVO2 / ORCA 的区别 + +| 维度 | RVO_Py_MAS | RVO2 / ORCA | +| --- | --- | --- | +| 核心方式 | 采样候选速度,过滤禁区 | 构造半平面约束,求最近安全速度 | +| 实现复杂度 | 低 | 更高 | +| 可读性 | 很直观 | 数学和工程结构更复杂 | +| 理论性质 | 较弱 | 更强 | +| 性能 | 小规模足够,规模大需优化 | 更成熟,适合大量 agent | +| 学习价值 | 很高,适合理解速度障碍 | 更适合工程使用和高性能仿真 | + +## 对 FishROV 的启发 + +如果 FishROV 后续要做自研鱼群避障,可以吸收它的核心结构: + +```text +目标速度 + -> 构造邻居/障碍的未来碰撞风险 + -> 在速度空间选择替代速度 + -> 优先保持目标意图 + -> 只有必要时才避让 +``` + +更适合 FishROV 的工程版本可以考虑: + +- 加空间哈希或网格邻居查询,避免全量两两比较。 +- 把 3D 鱼群投影到 XZ 平面做水平避障,再单独处理高度层。 +- 在候选速度里加入最大转向角、最大加速度、速度平滑约束。 +- 对不同鱼群状态加权,例如巡游、逃逸、聚集、追逐。 +- 增加右侧/左侧通行偏置,减少对称场景下的互相卡住。 +- 把“预计碰撞时间”和“当前重叠深度”作为调试指标输出。 + +## 结论 + +`RVO_Py_MAS` 最值得学习的不是它的具体 Python 代码,而是它的建模方式: + +```text +不要只在位置空间推开物体。 +要在速度空间判断:哪些速度会导致未来碰撞。 +``` + +它适合作为理解 RVO 思想和自研局部避障算法的入门参考;如果目标是直接上生产级大规模 agent 避障,RVO2 / ORCA 或项目内针对鱼群特征优化后的采样避障会更合适。 + +## 参考 + +- [MengGuo/RVO_Py_MAS](https://github.com/MengGuo/RVO_Py_MAS) +- [RVO_Py_MAS/RVO.py](https://github.com/MengGuo/RVO_Py_MAS/blob/master/RVO.py) +- [Reciprocal Velocity Obstacles for Real-Time Multi-Agent Navigation](https://gamma.cs.unc.edu/RVO/)