Files
worldmodel/plans/physics_engine_implementation.md

290 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "WorldModel 物理引擎集成方案"
date: 2026-05-28
draft: false
tags: [worldmodel, physics-engine, PRISM, 技术方案]
categories: [plans]
description: "为WorldModel室内场景添加物理引擎的完整技术方案,包括引擎选型、3D重建网格碰撞准备、PRISM空间记忆融合与实施路线图。"
---
# WorldModel 物理引擎集成方案 (v1.0)
## 1. 背景与动机
WorldModel的核心数据流(RoomPlan/ZED2i -> PRISM空间记忆)已覆盖"看见并记住"室内环境。要完成闭环,还需要让机器人在数字环境中能够与物体进行**物理交互验证**。这要求:
1. **碰撞检测**: 机器人在虚拟酒店房间中运动时,不会穿墙、撞翻物体
2. **对象操作模拟**: 开门、推拉椅子等动作可以在仿真环境中验证可行性
3. **物理属性学习**: 机器人通过交互获取"这个物体推得动还是推不动"的经验,反哺L4语义记忆
4. **合成数据生成**: 为视觉模型/行为克隆策略提供带物理标签的训练样本
## 2. 引擎选型对比
| | Bullet / PyBullet | NVIDIA PhysX (Isaac Sim) | Unity Physics (Jolt) | Unreal Engine 5 Chaos | MuJoCo |
|---|---|---|---|---|---|
| **许可证** | MIT 开源 | Apache-2.0 (PhysX) / NVIDIA专有(EZG) | MIT/Jolt-2.0 | Apache-2.0 (Chaos SDK部分可用) | 开源研究用 |
| **GPU加速** | CUDA/OpenCL插件可选 (cuBullet) | 原生硬件级(PhysX GPU | CPU为主,GPU开发中 | GPU RayTracing/Physics | 纯CPU物理步 |
| **ROS集成** | pybullet-ros, ros_control封装成熟 | Isaac ROS生态(需NVIDIA硬件) | 间接(ROS2 Bridge) | ROS2 Bridge存在但较新 | 需自定义wrapper |
| **机器人动力学** | KUKA/PR2模型现成,RBD引擎支持全身控制 | Robot Assets库丰富(nvidia-isaac-sim/robots) | 需手动配置 | Skeletal + Rigid body | MPC/整体制动强但仅运动学、无对象操作 |
| **网格碰撞精度** | ConcaveMesh(BVH)+Convex Decomposition工具链完整 | USDZ原生支持,ConvNv扩展做convex decomposition | OBJ->FBX需转换、材质丢失风险高 | 支持OBJ/FBX/GLTF但PBR物理参数需手动调 | 仅支持convex primitives(Box/Sphere/Capsule) |
| **室内重建网格兼容性** | OBJ/STL直接加载,pymeshlab+pybullet-convex-decomp处理 | 最佳(USDZ是NVIDIA生态标准) | OBJ->FBX需转换,材质丢失风险高 | 支持OBJ/FBX/GLTF但PBR物理参数需手动调 | OBJ->convex approximation(自动)|
| **团队熟悉度** | Python为主(Robotics生态已有) | 需学习Isaac Sim专用框架+CUDA工具链 | Unity C#简单但物理系统相对新 | UE5蓝图+CPP双栈,生态庞大 | 研究友好、功能受限(纯刚体)|
| **性能(帧率)** | 中等精度~10-30fps@中大型房间 | GPU并行,百万级物体(最快) | ~30fps @中型场景 | 高(GPU加速但需UE5渲染管线) | 最快可达10kHz+物理步,但仅刚体无网格碰撞 |
### **推荐方案:主从双引擎架构**
**主引擎: PyBullet + Bullet Physics Server(实时感知与操作层)**
理由:
- PRISM tools已有Python环境,PyBullet提供纯Python API无缝衔接ROS生态
- Mesh碰撞处理工具链最完整(pybullet_convex_decomp, pymeshlab脚本可复用)
- 轻量独立,不依赖NVIDIA GPU
**辅助引擎: NVIDIA Isaac Sim(高保真合成数据层)**
理由:
- 需要生成带精确物理标签的训练集时(如物体形变、流体交互),Isaac Sim是业界标杆
- 与RoomPlan的USDZ格式天然兼容(NVIDIA生态)
**备选快速验证: MuJoCo + MJCF (原型阶段)**
理由:确定PRISM-L4语义层需要哪些物理属性时,MuJoCo可以快速搭建"物体->可操作参数"的原型验证环境
## 3. PRISM x 物理引擎融合架构
### 数据层映射:PRISM四层如何承载"物体物理状态"
| PRISM层级 | 传统内容 | **新增物理字段**
---
| L1感知缓冲(~30Hz) | ZED2i当前帧点云/图像流 | 实时碰撞体包围盒(BVH)生成、接触力反馈(触觉传感器输入)|
| L2度量地图 | 3D体素网格+语义标签 | Mesh碰撞几何(每类家具->Bullet ConvexHull)、静摩擦系数mu_s、动摩擦系数mu_k、质量m |
| L3拓扑图 | Graph(Room->Corridor->Room),边权=距离/通行概率 | 边权重加入**物理约束**: "这个门需要开门空间>=0.8m"、通道净宽 |
| L4语义场 | Object属性查询("这把椅子是木质的")+LLM可问答性 | 物理交互标签: `"movable": true, "push_force_estimate_N":[15.0, 45.0], "friction":"medium"`;LLM可推理"这个物体重吗?推得动吗?"|
### 核心模块:Physics-PRISM Bridge (PPB)
```
+-------------+ 碰撞几何 +-----------+
RoomPlan/ZED2i --> | Mesh Processor| --------------> |Bullet Server| <-- robot_control_loop
(3D重建) +-------------+ ^(pybullet) |
^ +-----------+ V|
|| 物理属性注入 (10Hz状态更新) |Collision/Force Feedback|
|| vPRISM L1写入 +---> PRISM L1
PPB |<----------------------------------------------(碰撞事件写入L1缓冲) 物理状态推送|
Manager--|---> PRISM L2-L4更新: "椅子被撞了0.3m"
(ROS Node)|<---- "这扇门现在半开(角度120度)"
+--------+
|
ROS Topic: /prism/physics_state
```
**PPB 关键职责:**1. **从PRISM L4语义场拉取物体属性** ->为每个对象在Bullet中创建刚体
2. **将碰撞检测结果写回PRISM L1/L2** ->实时物理事件进入空间记忆3. **维护"已知交互历史"** ->L4中积累物体操作经验(LLM可查询)
### 新增PRISM管线:Pipeline E -- "物理巩固"在现有四个管线的第四个(记忆巩固 Pipeline D)之后,追加:
**Pipeline E: 物理知识巩固 (Physics Consolidation)**
- **触发**:每次有意义的物体交互(推门成功/失败、拿取物品)
- **数据源**: Bullet仿真 ->实际传感器验证对比差异(仿真到现实 gap度量)
- **写入目标**:L4语义场,更新物体的交互标签(摩擦力、重量估计修正)
- **频率**:非实时事件驱动,~1Hz或交互后批量写入
## 4. Mesh -> Physics几何转换管线
### 流程:3D重建网格 --> Bullet碰撞体RoomPlan USDZ/OBJ ---> OpenUSD/Pymeshlab处理->Convex Decomposition(BVPY/ICME) -> Bullet ConcaveMesh / ConvexHulls (静态几何: 每帧更新+动态刚体:可交互对象)
### 4.1 RoomPlan USDZ -> OBJ/Ply转换
- Apple RoomPlan输出USDZ格式,NVIDIA Omniverse USD Python API可直接解析(pxr.Sdf, usdGeom.Mesh)
- 对于非NVIDIA路径:使用opensubdiv + trimesh做 USDZ ->OBJ/Ply导出
### 4.2 Mesh简化与碰撞体生成- **静态物体**(墙壁、地板): Bullet ConcaveMesh (BVH树) -- 不需要convex decomposition
- **可交互物体**(椅子、门把手): Convex Decomposition ->分解为~5-20个convex hulls
- **推荐工具**:pybullet_convex_decomp(Bullet官方Python wrapper,支持GPU加速)
- **替代**:V-HACD (Virtual Hi-Arcade Convex Decomposition,精度最优但较慢)
- **快速方案**:pymeshlab的convex_decomposition filter
### 4.3 Mesh质量要求- **精度**:静态墙壁/地板<2mm偏差(L1感知缓冲中ZED2i提供)- **性能**:每个可交互对象<10个convex hulls(Bullet BVH查询在~1ms内)
- **更新频率**:房间结构(墙壁)只在离线建图时构建一次;家具在"差异检测管线"(PRISM Pipeline C)触发时才重建
## 5. PRISM L4语义场扩展字段草案 (JSON Schema)在现有L4的"物体属性查询结构"中新增物理交互标签:
```json
{ "object_id": "chair_room_102_A", // L4语义场中的唯一标识
"category": ["furniture","seat"], // RoomPlan类别(现有) "physics"{ // NEW: 物理交互标签
```jsonc
{
"object_id": "chair_room_102_A", // L4语义场中的唯一标识
"category": ["furniture","seat"], // RoomPlan类别(现有)
"// --- NEW: Physical Interaction Tags --""",
"physics":{"mass_estimate_kg":6.2, // kg可由PPB的convex hull+材料估计
"friction":{"static":0.45, // mu_s: 静摩擦系数
"dynamic":0.32 //mu_k:动摩擦系数 },
```
"mass_estimate_kg":6.2, // kg可由PPB的convex hull+材料估计
"friction":{"static":0.45, // mu_s: 静摩擦系数
"dynamic":0.32 }},"movable":true, // 是否可移动(门、椅子为true,墙/地板为false)
"movable_method":["push",,"pull"], // 支持的操作类型(推/拉/提)
"push_force_range":[15.0, 45.0], // N:推启动力和可接受上限力
"stability":{"is_stable_unassisted":true, // 不推就自己不会倒
"toppling_force_Nm":12.5 // N·cm:翻倒阈值
},
"interaction_history":[ // LLM可查询的交互经验 { "timestamp":"2026-05-30T14:22",
"action":"push", // 操作类型 "object_from_location_xyz":[1.2,-0.5,0.78], // 移动前位置(L2度量坐标)
"object_to_location_xyz":[1.8,-0.5,0.78], // 移动后位置
"force_applied_N":25.3, //实际施加力
"success",true // push成功false=卡住了/推不动 }
] "sim2real_gap_stats":{ //PPB仿真与现实对比的统计
"position_drift_m":0.023, //平均位置偏差(仿真-->现实) "friction_bias":-0.12, //摩擦系数偏差(仿真比现实高/低多少)
"last_updated":"2026-05-31" //最后一次校准时间 }
"// --- NEW: Interaction History (Pipeline E写入) --""",
"interaction_history":[ // LLM可查询的交互经验 { "timestamp":"2026-05-30T14:22", "action":"push", // 操作类型 "object_from_location_xyz":[1.2,-0.5,0.78], // 移动前位置(L2度量坐标)
"object_to_location_xyz":[1.8,-0.5,0.78], // 移动后位置
"force_applied_N":25.3, //实际施加力 "success",true // push成功 / false=卡住了/推不动 }
]
"// --- NEW: Simulation-Reality Gap (Pipeline E) --""",
"sim2real_gap_stats":{ //PPB仿真与现实对比的统计 "position_drift_m":0.023, //平均位置偏差(仿真-->现实) "friction_bias":-0.12, //摩擦系数偏差(仿真比现实高/低多少) "last_updated":"2026-05-31" //最后一次校准时间 }
"// --- NEW: Interaction History (Pipeline E写入) --""",
"interaction_history":[ //LLM可查询的交互经验 { "timestamp":"2026-05-30T14:22", "action":"push", // 操作类型 "object_from_location_xyz":[1.2,-0.5,0.78], // 移动前位置(L2度量坐标) "object_to_location_xyz":[1.8,-0.5,0.78], // 移动后位置
"force_applied_N":25.3, //实际施加力 "success",true // push成功 / false=卡住了/推不动 }
] "sim2real_gap_stats":{ //PPB仿真与现实对比的统计 "position_drift_m":0.023, //平均位置偏差(仿真-->现实) "friction_bias":-0.12, //摩擦系数偏差(仿真比现实高/低多少)
"last_updated":"2026-05-31" //最后一次校准时间
}
},}
```## 6. PRISM Pipeline E: "物理巩固"详细设计### 触发条件TRIGGERS= [
"碰撞事件": collision.force_magnitude > threshold_N, #有意义的接触(如门撞到墙壁)
"物体位移": abs(translation_delta_m)> threshold, #可移动对象被显著推动
"交互完成": action.success == true/false, #如开门/关门完成
"时间周期": every_30_minutes //定期同步仿真状态与现实(校准)
]
### Pipeline E执行流程:1. **读取**:从 PRISM L4语义场 ->获取该物体的当前物理属性
2. **对比**simulation_position(PyBullet中) vs actual_sensor_position (ZED2i/IMU实际测量位置)
3. **校准**:如果 drift > tolerance -->更新L4物理属性(摩擦力、质量估计)
4. **日志**interaction_history追加记录 ->L4语义场永久存储5. **通知**:向L3拓扑发送"通道通行性变更"(如果物体移动导致了新障碍)
```python
class PhysicsConsolidationPipeline: """PRISM Pipeline E:物理知识巩固 触发条件= collision detected / interaction complete/periodic sync """ def trigger(self, event: Union[CollisionEvent] | InteractionComplete]) -> None:
self.log(event)
prism_l4_object = prisms_semantic_layer.query_by_name(event.object_id))
# Step 1: Read L4物理属性(仿真状态) sim_mass = prism_l4_object.physics.mass_estimate_kg friction_estimated=self.estimate_friction_from_force_sensor(event.contact_force)
# Step 2: Read ZED2i/IMU真实测量(现实状态) actual_position=self.zed_2i_camera.get_object_pose(event.object_id))
# Step 3: Compute gap(仿真 -->现实) sim_position=self.get_simulated_object_pose(event.object_id))
# Step 4: Update L4语义场
if sim2real_gap> tolerance: self.update_prism_l4_physics(event.object_id,friction_estimated)
```
## 7. PPB ROS消息定义草案 (prism_msgs/PrismPhysicsState.msg)
```
# 每帧发布: /prism/l1/collision_events (30Hz)std_msgs/Header header
# 当前帧碰撞事件列表(可为空CollisionEvent[] collisions
message CollisionEvent {
string object_a # PRISM L4语义名称,如 "chair_01"
string object_b # PRISM L4语义名称,如 "wall_kitchen_east"
geometry_msgs/Vector3 contact_point # WGS坐标系中的碰撞点(L2度量)
geometry_msgs/Vector3 contact_normal #法线方向 float64 penetration_depth #穿透深度(mm), <0表示分离距离
geometry_msgs/Wrench contact_force #L1力觉反馈:力和扭矩}
#每50ms发布: /prism/l2/physics_mesh_state (20Hz)
std_msgs/Header header#所有动态刚体的当前位姿(用于L2度量地图中的物体定位)DynamicBodyState[] dynamic_bodies
message DynamicBodyState {
string body_name # PRISM L4语义名称,如 "door_hallway_02" geometry_msgs/Pose pose #6DoF位姿(位置+四元数)
float32 mass #kg, L4语义场中的物理属性查询结果}
#按需请求: /prism/l2/get_physics_properties (ROS Service)
---string object_name # 请求: L4语义名称(如 "chair_01")
---#响应:该物体的物理属性 (L4语义场中的值)string description #"可推动,木质框架"float32 friction_mu_static #静摩擦系数 mu_s \in [0.1, 1.5]float32 friction_mu_dynamic #动摩擦系数mu_k \in [0.1, 1.2]
float32 mass #kg:"中等重量,约5kg" \to 6.0bool is_movable #true/false: "椅子可以被搬走" \to truefloat32 push_force_min #启动推力估计(N)
```
## 8. Phase实现路线图(四阶段)### Phase 0:原型验证 (2周) **目标: "PyBullet能跑起一间酒店客房吗?**步骤1产** 产出物0.2读取一个RoomPlan样例(USDZ或OBJ),用trimesh导出为PLYphysics/demo/load_room.py) + screenshot
```
"0.3在PyBullet中加载房间几何为静态刚体,机器人URDF模型进入
"0.4加入一个动态物体(椅子),实现简单的推拽交互|Bullet仿真截图 + 操作日志
"0.5写一份README记录踩坑和经验教训|/plans/physics_engine_implementation.md#phase0的完成checklist和known issues
```
**交付**: 一个可以在终端跑的Python脚本,加载房间网格+URDF机器人,可视化窗口中可操作
### Phase 1: Mesh处理管线 (3周) **目标:** "从任意RoomPlan/ZED2i场景自动构建碰撞几何"
| 步骤 | 内容
---### Phase1.2 Mesh简化工具(减少三角面到collision-ready级别)| 使用pyfqmr或gptoolbox做mesh simplification
### Phase1.3 Convex Decomposition pipeline: V-HACD + pybullet_convex_decomp| 配置JSON支持自定义convex hull上限参数(每个对象max_hulls=10)
### Phase 1.4自动标注"静态 vs 动态"对象(基于RoomPlan语义层)| RoomPlan输出包含category: wall/furniture/door/cabinet标签,自动分类
### Phase 1.5集成测试: PRISM Pipeline A的输出(离线3D重建) -> PPB自动创建Bullet世界|端到端Pipeline测试脚本`physics/test_e2e_pipeline.py`+报告
### Phase 2: PRISM Bridge (4周) **目标:** "物理引擎数据进入PRISM四层记忆,形成闭环"
| 步骤 | PRISM对接点
---### Phase2.1 PPB ROS Node: /prism/physics_state | 定义ROS消息类型`PrismPhysicsState.msg`(包含所有碰撞体位姿)
### Phase 2.2 L1写入:将Bullet接触/碰撞事件推送至L1感知缓冲| topic `/prism/l1/collision_events`,格式: `{frame_id, object_a,object_b, contact_force}`
### Phase2.3 L4读写:将PPB从PRISM拉取的物体属性+写回的交互经验| ROS service `GetPhysicsProperties` / `UpdateInteractionHistory`,使用prism_ros_bridge的现有topic
### Phase2.4差异检测集成: PRISM Pipeline C触发时,对比当前物理状态与L2度量地图中存储的"理想几何"| 输出差异报告: `physics_consolidation_report.json`(哪些物体位置变了、被移动了)
### Phase2.5 L3拓扑图更新:物理约束影响通行性评估(半开门导致通道变窄)|L3 edge weight更新: `passability_score=base_passability x(1 - collision_risk_penalty)`### Phase3.2合成数据标注管线:从PyBullet世界随机采样物体位置/光照 -->渲染图像+ground truth标签| `physics/synthesis/generate_episode.py`,输出: RGB图像, depth图, semantic segmentation mask, object bounding boxes
### Phase3.3数据格式: ONNX-compatible dataset(与HuggingFace Hub集成)| HFDataset定义 + upload脚本 `physics/synthesis/upload_to_hf.py`
### Phase3.4机器人策略验证: PyBullet + ROS Control中的RL agent在仿真中学习"开门/推椅"|集成stable-baselines3(RLlib) + pybullet-ros,训练简单的push/grasp policy
### Phase 3.5合成数据质量验证:与真实场景对比分布差异(MMD / Fréchet Inception Distance) | `physics/synthesis/evaluate_fidelity.py`
## 9. 技术栈清单(新增依赖)### Python核心
```textpybullet>=3.2.x #Bullet Physics引擎Python绑定(主物理后端)pymeshlab==2023.12 #网格简化、convex hull计算
opensubdiv>=3.6 #OpenUSD/USDZ解析(非NVIDIA路径)pyfqmr #快速网格简化到collision-ready级别
trimesh>=4.0 #Mesh格式转换(USDZ/OBJ/PLY/FBX)
pybullet_convex_decomp #GPU加速凸分解(需要CUDA 12+)```### ROS生态
`textros-noetic-robot-base #URDF/RViz支持(ROS1 Noetic)
ros-humble-robot-base # ROS2 Humble对应包(备选/未来路径)
pybullet_ros # PyBullet与ROS通信bridge(如可用则集成,否则自建)
```### 辅助工具`textopensimplex #合成数据中的随机扰动生成(放置物体位置)huggingface_hub #合成数据集发布到HFDataset Hub```### GPU依赖(可选,Phase 1-2之后评估是否需要)
`text# NVIDIA CUDA 12.4+ + cuBLAS/cuSPARSE(用于cuBullet或pybullet_convex_decomp的GPU加速)
# Jetson Orin / RTX 4090(桌面测试环境)```
## 10. PRISM L4语义场LLM查询示例(集成后能力)
```
# 用户/策略模块可以向PRISM L4语义场发起LLM查询:> "房间102中,哪些椅子可以被搬动?"
>→从L4语义场返回: "chair_A(可推,mus=0.45), chair_B (固定在地) -->只有一把可以移动"
> " hallway走廊的通行性怎么样?">PRISM从L3拓扑+ L1最近碰撞事件回答: "当前通行概率72% -- 一把椅子被推到了走廊中央(见L1事件#34),移除后可以恢复95%"
> "如果我把桌子向右推2米,会撞到门吗?">PRISM调用PyBullet执行虚拟操作: "模拟结果显示不会碰撞。桌子最右边缘与门框距离0.4m(安全)"
> "这个房间里有哪些物体是半开着的,可能阻碍通行?">L1/L2碰撞检测返回: "门_厨房东(角度=45度), 窗柜抽屉拉出10cm"
```
## Appendix A. PyBullet + PRISM 集成架构代码框架### `physics/engine/bullet_server.py` -- Bullet Server(ROS Node)
```python
import pybullet as pclass PhysicsServer: """PyBullet服务端,作为独立的ROS Node运行"""
def __init__(self): p.connect(p.GUI) # GUI可选;headless用p.connect(p.DIRECT)
p.setGravity(0, 0, -9.81)
def load_room_mesh(self, room_usdz_path: str): """从RoomPlan/ZED2i的3D重建文件加载房间"""
```python
def load_room_mesh(self, room_usdz_path: str): """从RoomPlan/ZED2i的3D重建文件加载房间"""
def load_robot_urdf(self, robot_usdz_path: str): #修正:URDF文件 """加载移动机器人基座(带轮子/机械臂)"""
def set_object_interactivity(self, object_name: strmovable_bool) -> None): """控制PPB将PyBullet刚体标记为dynamic/static""" def get_collision_events(self) -> List[CollisionEvent]: """读取当前帧所有碰撞检测结果""" def sync_state_to_prism(self, prism_topic: str) -> None """将当前物理状态写入PRISM L1/L2 topic""" ```
### PRIMS --> PyBullet状态注入当PRISM Pipeline C(在线感知)检测到场景变化时,更新PyBullet中的碰撞体位姿:
```python
def on_prism_perception_update(self, updated_objects: List[PrismL4Object]):
"""PRISM感知更新 -->驱动PyBullet刚体状态修改"""
```