Hydra 教程(一):为什么机器人需要三维场景图

Hydra 教程(一):为什么机器人需要三维场景图

参考:Hydra、ChatGPT

Hydra 教程(一):为什么机器人需要三维场景图

SLAM(Simultaneous Localization and Mapping,同时定位与建图)可以估计机器人走过的轨迹,也可以重建周围几何;但机器人若要执行“去会议室找打印机”这样的任务,还必须知道哪些表面属于同一个物体、哪些自由空间彼此连通、物体属于哪个房间,以及地图在回环校正后怎样保持这些关系一致。

Hydra 的目标,就是在度量地图之上实时建立并维护这种多层空间表示。本篇只回答三个基础问题:

  1. 为什么 SLAM 地图不能直接承担全部空间推理?
  2. 动态三维场景图究竟保存什么?
  3. Hydra 怎样把局部传感器观测逐步变成可查询、可校正的全局结构?

读完本篇后,读者应能说清 Hydra 在机器人系统中的职责边界,并知道后续每篇文章解决哪一个尚未解决的问题。


1. SLAM 解决了定位和几何,但没有自动得到任务语义

典型 SLAM 系统主要估计两类结果:

机器人轨迹 {TWB(t)}和环境地图 M \text{机器人轨迹 } \{\mathbf{T}_{WB}(t)\} \quad\text{和}\quad \text{环境地图 } \mathcal{M}机器人轨迹{TWB(t)}环境地图M

其中,TWB(t)\mathbf{T}_{WB}(t)TWB(t)表示时刻ttt机器人机体坐标系BBB到世界坐标系WWW的位姿;M\mathcal{M}M可以是特征点、点云、体素、网格或占据栅格。

这些结果对定位和避障很重要,却不会自动回答下面的问题。下表中的 Object 指可独立引用的物体实例,Place 指自由空间骨架上的稀疏代表位置,Room 指由一组 Places 组织出的房间实例;这些表示将在后文正式定义。

任务问题仅有轨迹和几何时还缺少什么
“打印机在哪里?”哪些表面属于同一个打印机实例
“打印机在哪个房间?”Object、Place 和 Room 之间的归属关系
“从办公室能否到会议室?”自由空间的稀疏连通结构,而不只是表面点
“前方还有哪里没探索?”已知可达空间和未知空间的边界
“回到起点后为什么出现两份办公室?”回环约束以及几何、实体和层级的联合校正

这不是 SLAM 做得不够好,而是问题层次不同。SLAM 首先解决“机器人和几何在哪里”;任务规划还需要“这里有什么、彼此什么关系、应该通过哪些空间到达”。Hydra 消费上游定位结果和传感器观测,在其上构建面向空间推理的表示。

这种把抽象概念连接到实际物理实体的过程称为符号落地。例如,命令中的“打印机”只是一个符号;机器人必须把它对应到地图中的某个三维实例、位置和所属房间,这个符号才真正能够指导行动。

2. 同一个环境为什么需要多种表示

假设机器人进入一间办公室,看到墙、地面、桌子、椅子和打印机。不同表示回答的问题不同。

2.1 度量表示保存精确几何

度量表示中的位置和距离具有真实物理尺度。例如体素边长是0.1 m0.1\,\text{m}0.1m,网格顶点具有世界坐标,机器人可以计算自己离墙还有多远。

Hydra 使用的底层度量表示包括:

  • TSDF(Truncated Signed Distance Field,截断有符号距离场):融合多帧深度并描述观测表面附近的截断有符号距离。
  • 语义体素:把类别证据与体素几何共同融合。
  • 三角网格:把隐式距离场转成可显示、可分割的显式表面。
  • ESDF(Euclidean Signed Distance Field,欧氏有符号距离场):给自由空间位置提供到障碍的欧氏距离。
  • GVD(Generalized Voronoi Diagram,广义 Voronoi 图):在 ESDF 中找出同时受多个障碍表面限制的位置,形成自由空间中轴骨架。

这些表示精确,却非常密集。机器人若要查询“办公室里有哪些对象”,不应该每次都扫描数百万体素或网格顶点。

2.2 语义地图告诉机器人“这是什么”

语义地图在几何位置上附加类别信息,例如墙、地面、椅子或打印机。它把“这里存在表面”推进到“这里可能是某一类表面”。

但逐点或逐体素标签仍然是扁平表示。它可能有许多chair顶点,却没有明确说明这些顶点属于一把椅子还是两把椅子,也没有表示椅子和房间的关系。

2.3 实例与关系让语义能够被查询

为了让机器人引用一个具体实体,需要把许多底层证据聚合成一个实例节点:

许多 chair 网格顶点 -> Object O7 许多自由空间骨架体素 -> Place p12 一组相互连通的 Places -> Room R2

节点解决“有哪些实体”,边解决“实体之间有什么关系”。例如:

O7 -- p12 对象以哪个自由空间位置作为空间锚点 p12 -- p13 两个自由空间代表位置之间存在连接 R2 -- p12 这个 Place 被分配到哪个 Room

2.4 拓扑表示压缩“怎样连通”

这里的拓扑主要指连通关系。两条走廊即使长度略有误差,只要连接结构没有改变,拓扑仍可以保持一致。

Hydra 的 Places 图把连续自由空间压缩成稀疏节点和边:节点代表自由空间骨架上的位置,边代表底层几何证据支持的连接。它不取代精确地图,而是让路径搜索、房间发现和回环描述不必直接处理全部体素。

所以 Hydra 并不是在几种地图中选择一种,而是让它们分工:

体素和 Mesh:保留几何精度 Objects:表达可引用实体 Places:表达自由空间拓扑 Rooms / Building:表达更高层空间组织 Agents:表达机器人经过这些空间的时间轨迹

3. 动态三维场景图到底是什么

在时刻ttt,可以把 Hydra 的动态场景图写成:

Gt=(Vt,Et,At,Mt) \mathcal{G}_t=(\mathcal{V}_t,\mathcal{E}_t,\mathcal{A}_t,\mathcal{M}_t)Gt=(Vt,Et,At,Mt)

其中:

  • Vt\mathcal{V}_tVt是节点集合,例如 Objects、Places、Agents、Rooms 和 Building。
  • Et\mathcal{E}_tEt是边集合,表示同层邻接或跨层归属。
  • At\mathcal{A}_tAt是节点和边的属性,例如位置、语义类别、清障距离和时间戳。
  • Mt\mathcal{M}_tMt是挂在图上的全局三角网格,它提供稠密几何证据,但网格顶点不需要全部成为普通图节点。

下标ttt不表示每一帧保存一份完整图副本,而表示同一张图会随着新观测、归档、节点合并和后端优化持续变化。

3.1 DSG 是分层图,但不是一棵树

DSG 是Dynamic Scene Graph的缩写,中文可译为动态场景图。它具有层级关系,却不能简单画成一棵树,因为每一层内部还可能有横向边和回路。

例如:

Building B0 | Room R0 ----- Room R1 / \ | p0 -- p1 ------ p2 | | O3 O4
  • B0 -> R0是高层到低层的包含关系。
  • R0 -- R1是两个房间的邻接关系。
  • p0 -- p1 -- p2是自由空间拓扑。
  • p0 -> O3表示 Object 与附近 Place 的跨层锚定。

只要存在p0--p1--p2--p0一类同层回路,整张图就不是树。层次只规定不同抽象尺度怎样组织,不要求删除同层拓扑。

3.2 Layer 和 partition 分别解决什么问题

Layer按实体的抽象层次组织节点;partition则允许同一层号中保存生成方式或所有者不同的子图。当前 C++ 仓库的默认命名层可以概括为:

名称默认层键一个节点表示什么主要证据来源
OBJECTS(2,0)(2,0)(2,0)一个三维语义对象实例语义 Mesh 顶点聚类
AGENTS层号 2、按机器人前缀分区机器人在某个时刻的离散位姿上游里程计或位姿图
PLACES(3,0)(3,0)(3,0)三维自由空间骨架代表位置ESDF、GVD 和图压缩
MESH_PLACES(3,1)(3,1)(3,1)指定语义表面的二维区域Mesh 分割、边界和椭圆近似
ROOMS(4,0)(4,0)(4,0)一组 Places 形成的几何房间Places 图的多尺度聚类
BUILDINGS(5,0)(5,0)(5,0)当前 Rooms 的顶层聚合Room 集合

OBJECTSAGENTS共享层号 2,却位于不同分区;PLACESMESH_PLACES共享层号 3,也位于不同分区。因此层号相同不表示它们是同一种节点,partition 也不表示父子高低关系。

Frontier(前沿)表示已知可达空间旁边、值得继续观测的未知边界候选。当前实现把 Frontier 节点放入PLACES层,但用属性区分它不是由 GVD 产生的真实 Place。这样探索模块可以把未知边界候选连接到真实 Places 图,而不必再建立一套完全独立的导航骨架。

3.3 同层边与跨层边不能按同一种语义解释

同层边连接同一个层键中的节点:

  • Place–Place 边表示自由空间连接,并可携带路径瓶颈清障值。
  • Agent–Agent 边表示轨迹状态之间的图连接。
  • Room–Room 边表示底层 Places 存在跨房间邻接。

跨层边连接不同抽象尺度:

  • Room–Place 表示几何房间成员关系。
  • Place–Object 表示对象的空间锚点。
  • Building–Room 表示顶层包含关系。

同一个通用EdgeAttributes类型可以在不同层承载不同意义,所以不能看到weight就假定它一定是欧氏距离,也不能把所有跨层边都当作传感器直接测量。每类边都有自己的证据来源和接受条件。

4. Hydra 怎样从观测逐层得到这些节点

高层节点不是由一个神经网络一次性输出。Hydra 同时维护几何链、语义链和轨迹链,再通过图边把它们连接起来。

Object--Room 图

Room 邻接

跨层锚定

可配置锚定

上游位姿 / 里程计

局部重建

深度图或点云

像素或点语义

TSDF / 语义体素

度量-语义 Mesh

ESDF / GVD

Objects

Mesh Places

Places

Agents

Frontiers

Rooms

Building

Neural Tree 房间类别

这张图中有几个必须从一开始就明确的边界。

**第一,机器人位姿通常来自上游定位系统。**Hydra 可以接收视觉惯性里程计、激光里程计、融合定位或数据集真值提供的位姿,再用它把观测放进共同坐标系。Hydra 的核心职责不是替代所有前端定位算法。

**第二,Objects 依赖语义输入。**深度只能说明表面在哪里,不能自己产生chairtable等类别。语义通常来自二维或三维感知网络,再由 Hydra 融合和聚类。

**第三,Rooms 的实例边界和语义类别是两步。**Room Finder(几何房间提取器)根据 Places 形成 Room 实例;2024 论文再用 Neural Tree(神经树)推断officebedroom等类别。Neural Tree 先把 Object–Room 图组织成 H-tree 计算结构,再进行可学习的图消息传递。当前核心 C++ 仓库创建几何 Room 时先写占位标签,房间分类网络另在 Hydra-GNN 发布。

**第四,Building 在当前 C++ 路径中是单一聚合根。**它把当前 Rooms 连接到B0,不是一套能够在室外地图中自动分割多栋建筑的算法。

5. 在线流水线为什么分成多个模块

如果所有步骤都在每一帧串行处理整张地图,计算量会随探索范围不断增长。Hydra 把快速局部更新和较慢全局推理分开,并通过增量消息和图快照衔接。回环检测(Loop Closure Detection,LCD)负责识别当前区域是否与历史区域重合。

输入与位姿同步

Active Window / Reconstruction

Graph Builder

Backend

回环检测 LCD

优化后的全局 DSG 与 Mesh

5.1 输入与局部重建回答“这一帧改变了哪里”

输入端把带时间戳的位姿、深度或点云、颜色和语义组织成观测包。局部重建只更新当前观测影响的体素 block;一个 block 是按固定尺寸组合在一起、可整体分配和更新的一组体素。模块随后输出发生变化或离开活动范围的增量。

这里的active window(活动窗口)不是一张独立地图,也不等于相机当前视锥。它是一种生命周期和计算预算策略:机器人附近的稠密块继续参与实时融合,较远的历史块可以归档,也就是停止局部高频更新但保留必要历史结果;稀疏高层节点仍可留在全局场景图中。

5.2 Graph Builder 回答“这些变化对应哪些图实体”

前端 Graph Builder 消费局部重建输出,增量更新 Mesh、Objects、Places、Frontiers、Mesh Places 和 Agents,并建立必要的跨层关系。它追求低延迟,因此主要处理本轮变化,而不是反复从空图重建全部层。

一轮前端提交带有时间戳和递增序号。序号表示“这是第几版完整前端更新”,时间戳表示“观测发生在什么时候”;两者用途不同。

5.3 Loop Closure 回答“这里以前是否来过”

回环检测模块从已归档的历史子图和当前查询位置生成描述子,先检索候选,再通过三维对应和鲁棒配准验证几何一致性。描述子相似只能说明“可能是同一地点”,只有通过几何验证的结果才适合成为后端约束。

5.4 Backend 回答“怎样让过去和现在重新一致”

后端接收前端位姿图、Mesh 形变图、回环约束和共享 DSG 快照。它优化 Agent 位姿和形变控制点,再校正 Mesh、Places、Objects 等状态,并合并回环后重合的重复节点。Rooms 和 Building 依赖更新后的低层结构重新生成。

前端、回环和后端可以以不同频率运行,因此代码维护分别服务后端和回环检测的共享图快照。这样较慢的全局计算不会阻塞每一帧局部重建,但消息中的序号必须与图快照对应,避免把某轮增量应用到另一版图上。

6. 为什么“增量”和“层次化”必须同时存在

这两个词解决的是不同问题。

6.1 增量更新控制每轮计算量

机器人新观察到一段走廊时,真正变化的通常只是附近一小片体素、Mesh 和图节点。增量系统传播:

哪些 block 更新了 哪些 Mesh 顶点新增或归档了 哪些 GVD 体素成立或失效了 哪些节点、边和属性发生变化

它避免每一帧重新扫描整栋建筑。

6.2 层次化表示控制长期存储和查询成本

即使每轮只处理局部变化,机器人长期运行后仍会积累大量几何。层次化表示把不同任务需要的信息压缩到合适尺度:

  • 碰撞与表面检查使用体素或 Mesh。
  • 局部连通查询使用 Places。
  • 对象查询使用 Objects。
  • 跨区域推理使用 Rooms 和 Building。

高层不是低层的无损副本。例如一个 Place 只能摘要一簇自由空间骨架证据,不能恢复所有原始深度像素。这个有意的抽象损失换来了更快的搜索和更清晰的关系结构;需要精确几何时,系统仍然可以回到底层 Mesh 或体素。

7. “Dynamic” 不等于自动跟踪所有运动物体

Hydra 中的“动态”首先表示地图状态会变化:

  1. 新观测会新增或更新节点与边。
  2. 节点可以从 active 变为 archived,也可以因证据失效而删除。
  3. 回环会改变历史轨迹和地图位置。
  4. 重合实体可以合并,Rooms 可以按最新 Places 重建。

因此:

archived != deleted 图会动态更新 != 系统自动完成多目标运动跟踪

当前对象提取主要从累计语义 Mesh 中形成实例,并不等同于带速度状态、运动模型和数据关联的完整动态物体跟踪器。动态类别是否进入静态重建,还取决于上游语义、掩码和系统集成策略。

8. 场景图怎样服务一个具体机器人任务

考虑任务:

去会议室找到打印机,并停在打印机旁边的可通行位置。

完整推理可以分为四个尺度。

第一步:找到目标类别和实例。

Neural Tree 或外部房间语义模块给 Room 提供conference_room类别;Object 层提供printer实例。若系统只有几何 Room 而没有类别模型,就无法仅凭 Room ID 回答“哪个是会议室”。

第二步:沿跨层关系完成空间落地。

printer Object -> 附近的 Place -> 所属 Room

这把“打印机”从一个类别词变成世界坐标中的具体实例和可接近空间。

第三步:在高层和低层分别搜索。

Room 图可以先给出要经过的区域序列;Places 图再提供区域内部的稀疏连通骨架,并用清障属性帮助过滤过窄连接。

第四步:交给导航系统生成可执行轨迹。

Hydra 提供空间知识和拓扑证据,但它不是完整运动规划器。机器人半径、地面坡度、动力学、局部避障和控制约束仍应由导航栈处理。Place 边存在也不等于任意机器人都能无条件通过。

这个例子说明 Hydra 的价值不在于替代 SLAM 或 Navigation,而在于把二者之间缺少的实体、语义、拓扑和层级关系组织起来。

9. 阅读当前项目时必须区分的系统边界

能力完整研究系统中的位置当前仓库阅读结论
机器人定位上游视觉惯性里程计(VIO)、激光惯性里程计(LIO)、融合定位或真值轨迹Hydra 接收位姿,不应默认它在本仓库内完成全部定位
语义分割上游语义网络Hydra 融合语义结果;真实模型可由外部semantic_inference等提供
在线 ROS 接口Hydra-ROS当前核心仓库主要提供算法模块和接口
房间几何实例Hydra Room Finder当前 C++ 路径已实现
房间语义类别2024 论文 Neural Tree分类网络单独在 Hydra-GNN 发布;Room Finder 本身不是分类器
回环后全局校正Hydra Backend + 外部形变图优化库 Kimera-PGMO当前仓库封装并使用形变图与场景图更新逻辑
最终运动规划和控制下游 NavigationPlaces 和 Rooms 提供图结构,不直接输出完整控制轨迹
动态物体跟踪可扩展的上游/下游能力“Dynamic Scene Graph” 不能直接等同于多目标跟踪器

这张边界表会贯穿后续文章。若一项机制来自论文或外部仓库,正文会明确标记,而不会因为它属于“Hydra 系统”就暗示当前目录内一定存在对应实现。

10. 建立一个不会混乱的心智模型

可以把 Hydra 记成连续的三次压缩和一次全局校正:

第一次压缩:多帧观测 -> 稳定的度量—语义地图 第二次压缩:稠密几何 -> Objects 和 Places 等稀疏实体 第三次压缩:局部实体 -> Rooms 和 Building 等层级结构 全局校正:回环约束 -> 轨迹、Mesh 和场景图重新一致

每次压缩都会丢掉一部分低层细节,却保留下一类任务真正需要的状态。正因为底层几何和高层图同时存在,机器人才能在“精确到厘米的表面”和“可以用语言查询的房间与对象”之间切换。

下一篇将从第一步开始:上游位姿、深度、点云和语义具体怎样进入同一个坐标系,并逐帧形成 TSDF、语义体素、Mesh 和 active window。


实现证据索引

正文按概念组织,下面只列支撑本篇关键结论的实现位置。

结论证据层级位置
本仓库用于实时增量构建三维场景图当前仓库说明README.md
默认层名和LayerKey当前代码include/hydra/common/shared_dsg_info.h::SharedDsgInfo::Config
前端、后端和 LCD 使用独立共享图状态当前代码include/hydra/common/hydra_pipeline.hsrc/common/hydra_pipeline.cpp
模块间使用 Backend/LCD/回环队列当前代码include/hydra/common/pipeline_queues.h
Graph Builder 更新 Mesh、Places、Frontiers、Objects、Mesh Places 和 Pose Graph当前代码src/frontend/graph_builder.cpp::GraphBuilder
后端和 LCD 接收同一轮前端序号对应的图快照当前代码src/frontend/graph_builder.cpp::GraphBuilder::spinOnce
Room 分类使用 Neural Tree2024 论文设计doc/paper_translation/hydra_foundations_2024/hydra_foundations_2024_zh.html第 3.4.2 节
Room 分类网络独立发布当前仓库说明README.md中 2024-06-26 更新与 Hydra-GNN 链接
C++ Room Finder 创建几何 Room 时初始化占位标签当前代码src/rooms/room_finder.cpp::RoomFinder::makeRoomLayer
Building 当前创建固定B0聚合根当前代码src/backend/update_buildings_functor.cpp