chore: 初始提交,项目规划文档

This commit is contained in:
zjk
2026-08-27 22:27:40 +08:00
commit cfc9485ce1
2 changed files with 304 additions and 0 deletions
+284
View File
@@ -0,0 +1,284 @@
# H100 水下无人航行器 6-DOF 仿真与运动控制项目规划
> 项目代号:h100-control
> 目标:构建 H100 型 AUV/ROV 的六自由度(6-DOF)运动仿真平台,并在此之上开发闭环运动控制器(深度保持、定点/定速、航迹跟踪等)。
---
## 1. 技术选型
| 项 | 选择 | 说明 |
|---|---|---|
| 语言 | Python ≥ 3.10 | 开发迭代快,数值生态完善 |
| 数值计算 | NumPy / SciPy | 状态向量运算、线性代数 |
| 时间积分 | SciPy `scipy.integrate.ode`(rk45/rk853 自适应步长,C 实现) | 不自研积分器;Python 循环管控制周期,C 积分管周期之间 |
| 旋转 | SciPy `scipy.spatial.transform.Rotation` | 欧拉角/旋转矩阵/四元数互转、增量旋转组合,零手推公式 |
| QP 求解 | `cvxpy` + OSQP | 推力分配带约束 QP(热启动,单步 µs–ms);欠驱动基线用 NumPy 伪逆 |
| 经典控制 | `python-control` | `control.lqr` 直接解 LQR 增益,兼做阶跃/Bode 频率响应分析 |
| 滤波 | `scipy.signal.lfilter` / `filterpy`(预留) | 传感器一阶延迟;EKF 导航仅在可选项阶段使用 |
| 参数标定 | `lmfit` / `scipy.optimize` | M6 用海试数据拟合阻尼 D、附加质量 M_A、推力效率 η_t |
| 配置 | PyYAML + pydantic | 参数文件化 + 模型级校验,免改代码 |
| 数据记录 | pandas → CSV(可选 HDF5) | 便于离线分析与对比 |
| 可视化 | Matplotlib + plotly(可选交互 3D) | 2D 曲线 + 交互式 3D 轨迹/姿态 |
| 测试 | pytest | 每层模块可独立单测 |
| 依赖管理 | `requirements.txt` + `pyproject.toml` | |
> **原则:不重复造轮子** —— 旋转、ODE 积分、QP、LQR、滤波、参数标定都有成熟库(多为 C/Cython 后端);项目代码只保留 H100 特有的物理组装、场景与控制逻辑。
> 后续若需实时性(>1 kHz)或联合仿真,可将 `dynamics/` 层单独翻译为 C++ 并通过 pybind11 暴露,Python 接口保持不变,目录结构无需改动。
---
## 2. 目录结构
```
h100-control/
├── PROJECT_PLAN.md # 本规划文档
├── README.md # 快速上手:安装、运行、看结果
├── requirements.txt
├── pyproject.toml
│
├── config/ # ── 全部参数配置(YAML,改参数不改代码)
│ ├── vehicle.yaml # 车体:质量、惯性张量、附加质量、重心/浮心坐标、浮力
│ ├── thrusters.yaml # 推进器:推力型/泵喷、安装位置、安装方向、效率、推力上限
│ ├── controller.yaml # 控制器:级联 PID 增益、采样/更新周期
│ ├── sensors.yaml # 传感器:噪声标准差、一阶延迟、量程
│ └── scenarios/ # 仿真场景预设(每个文件定义一个工况)
│ ├── nominal.yaml # 静水、无扰动,基准工况
│ ├── current.yaml # 均匀洋流 / 分层洋流
│ ├── maneuver.yaml # S 形机动 / 正弦横航
│ └── disturbance.yaml # 波浪/外推力扰动
│
├── src/
│ └── h100/ # Python 包
│ ├── __init__.py
│ ├── dynamics/ # ── 动力学层(物理模型核心)
│ │ ├── kinematics.py # 姿态运动学:Rotation.from_rotvec(ω·dt) 增量旋转,不手推四元数代数
│ │ ├── equations.py # 6-DOF 刚体动力学方程(Newton-Euler 组装)
│ │ ├── hydrodynamics.py # 水动力:附加质量 C(ν)ν、线性+二次阻尼 D(ν)ν
│ │ ├── gravity.py # 重力/浮力 g(η):由重心/浮心几何计算
│ │ └── thruster.py # 推进器数学模型 + 推力分配(基线 NumPy 伪逆;带限幅约束 QP → cvxpy/OSQP)
│ │
│ ├── control/ # ── 控制层
│ │ ├── base.py # ControllerBase 抽象接口:update(dt, state) -> v_des
│ │ ├── cascade_pid.py # 级联 PID:外层位置/姿态 → 内层速度/角速度(基线)
│ │ ├── lqr.py # LQR(扩展:python-control 的 control.lqr + 增益调度)
│ │ └── backstepping.py # 反步法(扩展:非线性鲁棒)
│ │
│ ├── sensors/ # ── 传感器层(含噪声与延迟,闭环真实性关键)
│ │ ├── base.py # SensorBase:numpy 噪声 + scipy.signal.lfilter 一阶延迟
│ │ ├── imu.py # 陀螺/加速度计
│ │ ├── dvl.py # 多普勒测速仪(体坐标速度)
│ │ ├── depth.py # 压力深度计
│ │ └── ekf.py # EKF 导航(可选扩展:filterpy)
│ │
│ ├── environment/ # ── 环境层
│ │ ├── current.py # 洋流:均匀流 / 随深度分层流
│ │ └── disturbance.py # 外力/力矩扰动:正弦、阶跃、随机(海况模拟)
│ │
│ ├── sim/ # ── 仿真引擎(总装与主循环,时间积分直接用 SciPy)
│ │ ├── world.py # World:车体 + 环境 + 传感器 + 控制器 装配,输出 ODE 右端函数
│ │ ├── recorder.py # 时序记录:状态、控制量、误差 → CSV
│ │ └── sim.py # Simulation 主类:load_scenario() → 控制周期循环 + f.integrate() → run()
│ │
│ └── utils/ # ── 公共工具
│ ├── rotation.py # 薄封装:scipy.spatial.transform.Rotation + NED 约定映射
│ └── config.py # pydantic 模型:YAML 加载、字段校验、默认值合并
│
├── scripts/ # ── 各实验运行入口(薄封装,调用 sim 包)
│ ├── run_free_motion.py # 自由运动/漂移:无控制,验证动力学正确性
│ ├── run_depth_hold.py # 深度保持(单回路经典基准)
│ ├── run_velocity_hold.py # 定速/定点悬停
│ ├── run_waypoint_nav.py # 航点/三维轨迹跟踪任务
│ └── run_maneuver.py # 机动性能:S 形、正弦横航
│
├── tests/ # pytest
│ ├── test_rotation.py # 旋转/四元数变换、正交性、对偶性
│ ├── test_dynamics.py # 平衡点验证、能量耗散、零输入自由运动衰减
│ ├── test_thruster.py # 推力分配:满推可行域、欠驱动约束
│ └── test_pid.py # 单轴阶跃响应稳定性
│
├── results/ # 仿真输出(.gitignore,自动生成)
│ └── <exp_name>/trajectory.csv, control.csv, summary.json
├── data/ # 外部数据:参考轨迹、实船海试数据(对比用)
└── .gitignore
```
---
## 3. 总体架构
### 3.1 分层架构与数据流(每个仿真步 dt)
```
┌─────────────────────────────────────────────────────────────┐
│ Scenario(场景) │
│ 参考指令 r(t):位置/速度/姿态 + 洋流/扰动参数 │
└──────────────┬──────────────────────────────────────────────┘
│ 参考指令
▼
┌──────────────────────────┐
│ Controller 控制层 │ 输入:传感器状态(含噪声/延迟)
│ 级联 PID(基线) │ 输出:期望线速度/角速度 ν_d(体坐标)
└──────────────┬───────────┘
│ ν_d
▼
┌──────────────────────────┐
│ Thruster 推力分配 │ ν_d → 期望合力/力矩 τ = B·u
│ 伪逆 / QP(含推力限幅) │ 输出:各推进器推力 u
└──────────────┬───────────┘
│ τ
▼
┌──────────────────────────┐
│ Dynamics 动力学层 │ M(ν̇) + C(ν)ν + D(ν)ν + g(η) = τ
│ SciPy rk45 积分 │ 环境洋流/扰动在此叠加
└──────────────┬───────────┘
│ 新状态 (η, ν)
┌──────┴────────────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Sensors │ │ Recorder │
│ 噪声+延迟 │ │ CSV 记录 │
└───────┬───────┘ └───────────────┘
└──→ 反馈回 Controller(闭环)
```
### 3.2 仿真主循环(伪代码)
```python
from scipy.integrate import ode
# world 把车体/环境/传感器装配好,暴露 ODE 右端 f(t, y)(y=[p, q, v]),
# 本控制周期内的推进器力 τ 以全局量形式被 f 引用
f = ode(world.dynamics_rhs, t0, y0).set_integrator("rk45", rtol=1e-8, atol=1e-10)
T_c = 0.02 # 控制周期 100 Hz
t = t0
while t < t_end:
sd = world.sensors.read(t) # 1. 传感器读数(噪声+延迟)
v_d = controller.update(T_c, sd, ref(t)) # 2. 控制器 → 期望速度 ν_d
u = world.thrusters.allocate(v_d, sd) # 3. 推力分配(限幅)
world.set_forces(u) # 本周期内 τ 恒定
y = f.integrate(t + T_c) # 4. SciPy C 积分器自适应步长推进
t += T_c
world.recorder.log(t, sd, v_d, u) # 5. 记录
```
> **为什么这样用库**:`solve_ivp` 是自适应步长的黑盒,内部步长不受控,没法在固定控制周期处插入控制律;
> `scipy.integrate.ode(...).integrate(t_next)` 则允许 Python 循环按 `T_c` 精确调度控制律,
> 周期之间的积分由 C 实现的自适应 RK45 完成——**零自研积分器代码**,且比纯 Python 逐步 RK4 快一个量级以上。
> 无控制的开环验证(M2 自由运动)直接用 `solve_ivp(t_eval=...)` 一次调用即可,更快。
### 3.3 模块职责边界
| 层 | 输入 | 输出 | 不做什么 |
|---|---|---|---|
| `dynamics` | τ、环境力、状态 | 新状态 (η, ν) | 不感知参考指令、不含控制逻辑 |
| `control` | 传感器状态、参考指令 | 期望速度 ν_d | 不直接输出推进器量、不含物理参数 |
| `thruster` | ν_d、当前速度 | 推进器推力 u | 不含姿态换算 |
| `sensors` | 真实状态 | 带噪声/延迟的读数 | 不含滤波算法(可加 EKF 扩展目录) |
| `sim` | 场景 + 配置 | 实验结果 CSV | 只负责装配与循环,无算法 |
> 原则:**每层只依赖下层接口**,上层通过 YAML 配置切换(换控制器=换 `controller:` 一行,换工况=换场景文件)。
---
## 4. 数学模型定义(实现口径,写代码前对齐)
### 4.1 坐标系与符号
- 惯性系 N:右手系,x 指向北,y 指向东,z 指向地心(**z 向下为正**,水下常用约定)
- 体坐标系 B:x 指向艏,y 指向右,z 指向下
- 位姿 η = [pᵀ, φ, θ, ψ]ᵀ(位置 + 欧拉角:横滚 φ、俯仰 θ、航向 ψ,3-2-1 ZYX)
- 速度 ν = [u, v, w, p, q, r]ᵀ(体坐标系线速度 + 角速度)
- 姿态用**四元数**在仿真内部存储(避免万向锁),欧拉角仅用于日志与展示;`utils/rotation.py` 提供全部互转
### 4.2 6-DOF 刚体方程
```
M ν̇ + C(ν) ν + D(ν) ν + g(η) = τ_prop + τ_current + τ_dist
```
- `M = M_RB + M_A`:刚体惯性(含浮力减重效应)+ 附加质量张量(9×9,由 `vehicle.yaml` 配置)
- `C(ν) = C_RB(ν) + C_A(ν)`:科氏力与向心力项(由 M 反对称性质推导生成,不手填)
- `D(ν) = D_L + D_Q·|ν|`:线性阻尼 + 二次阻尼(由海试/经验公式标定)
- `g(η)`:重力/浮力,由重心 z_g、浮心 z_b、质量 m、排水体积 Δ 计算,在 N 系中 (0,0,ρgΔ−mg) 经 R(η)ᵀ 变换进 B 系
- 运动学:ν̂_body → ν̂_inertial 映射、四元数 q̇ = ½ q ⊗ [0, ω]
### 4.3 推进器与分配
- 单推进器:`F = η_t · sgn(ω) · k · ω²`(电机/泵喷通用,`thrusters.yaml` 给位置 p_i 与单位方向 d_i)
- 广义力:`τ_prop = Σ (F_i·d_i ⊕ p_i×(F_i·d_i)) = B u`,B ∈ R⁶ˣⁿ
- 分配律:
- 六自由度全驱动(n≥6 且 B 满秩):QP 最小化 `‖u‖²`,约束 `u_min ≤ u ≤ u_max`
- 欠驱动(无横推/前泵喷双推 + 尾桨等):伪逆 + 死区映射,文档中显式标注可达速度子集
- **H100 具体推进器数量/布局待确认**,先按 `thrusters.yaml` 参数化,文档示例以 6 推进器(4 斜置 + 2 纵向)为基准
### 4.4 传感器模型
- 读数 = 真实值(延迟 τ) + 零偏 + 白噪声(σ,可配)
- IMU/DVL/深度计各自独立参数,**控制器只能读传感器输出**,禁止直接读真值(防仿真失真)
---
## 5. 控制器设计路线
1. **M3 基线:级联 PID**
- 外层(导航系):位置误差 → 期望速度 ν_d^N;姿态外环:欧拉误差 → 期望角速度
- 内层(体坐标):速度跟踪 PID(可带前馈项 C(ν)ν + D(ν)ν)
- 每个被控通道独立增益组,全部 YAML 可调,含积分限幅(防 windup)
2. **M4 扩展:LQR** —— 线性化均衡点,`python-control` 的 `control.lqr(A,B,Q,R)` 解增益,随深度调度;用于对比 PID 性能
3. **M5 扩展:反步法/滑模** —— 显式处理 C(ν)、D(ν) 非线性与扰动,鲁棒性对比
4. 所有控制器实现 `ControllerBase` 接口(`update(dt, state, ref) -> v_des`),实验脚本中一键切换
### 性能指标(验收口径)
| 任务 | 指标 |
|---|---|
| 深度保持 | 稳态误差 < 0.1 m,超调 < 5%,恢复时间 < 10 s(±1 m 阶跃) |
| 定点悬停 | 三维位置 RMS < 0.2 m(静水)、< 0.5 m(含 0.2 m/s 洋流) |
| 航迹跟踪 | 直线/waypoint 平均横向偏差、最大航向偏差、稳态跟踪误差 |
| 机动 | S 形机动最大偏航延迟、侧向漂移量 |
---
## 6. 开发里程碑
| 阶段 | 内容 | 交付物 / 验收 |
|---|---|---|
| **M1 骨架** | 工程脚手架、配置加载、旋转工具 + 单测、SciPy 积分管线跑通 | `pytest` 全绿 |
| **M2 动力学** | 6-DOF 方程、水动力、重力浮力、自由运动验证 | 静水自由释放:偏离平衡后稳定衰减回平衡点(能量单调减);零输入不动 |
| **M3 执行与单回路** | 推进器模型 + 推力分配、级联 PID 深度保持 | 深度阶跃响应达标(§5 指标);`run_free_motion.py`、`run_depth_hold.py` 出图 |
| **M4 全通道控制** | 三位置 + 三姿态全级联、定点/定速/航点任务 | 三维跟踪演示脚本 + 性能报告(CSV + 图) |
| **M5 鲁棒性与对比** | 洋流/扰动场景、LQR/反步法实现、多控制器对比 | 同一工况下 PID vs LQR vs 反步对比表与轨迹图 |
| **M6 工程化** | 3D 可视化(plotly)、`lmfit` 海试数据参数标定(D、M_A、η_t)、实船数据对比(如有) | README 完整使用文档 |
---
## 7. 测试策略
- **单元测试**(`tests/`,pytest)
- 旋转:正交性 R·Rᵀ=I、欧拉-四元数往返一致(容差 1e-12)
- 动力学:零输入在平衡点不动;释放扰动后总机械能单调下降;M 阵对称正定
- 推力分配:给定 ν_d 重构 τ 误差 < 1e-9;满推时不越限
- **数值实验**(脚本即测试):每个 `scripts/run_*.py` 内置断言(收敛/误差阈值),失败时非零退出,可挂 CI
- **基准回归**:`results/baseline/` 保存 M3 完成的基准 CSV,后续改动跑 diff 防止物理模型被无意破坏
---
## 8. 编码约定
- 状态向量恒定使用体坐标速度 ν(方程内部),导航系位置 p ∈ R³ 独立存储
- 所有物理参数只出现在 `config/*.yaml`,代码中禁止硬编码数值(测试数据除外)
- 时间单位 s、力 N、长度 m、质量 kg、角速度 rad/s,全程 SI
- 类型注解 + docstring(含公式来源编号);`ruff` + `mypy` 常规检查
- 仿真种子:随机项(传感器噪声、扰动)由场景文件提供 `seed`,结果可复现
---
## 9. 待确认事项(开工前对齐)
1. **H100 推进器配置**:数量、类型(电机桨 / 泵喷)、安装位置角度、最大推力 —— 决定 B 阵与欠驱动程度
2. **车体参数来源**:CAD 质量属性 + 拖曳水池/拖曳试验水动力系数,还是先用文献典型值起步
3. **控制器需求**:是否需要自主避碰/路径规划(如需,后续新增 `planning/` 层,接口预留于 `control/base.py` 之上)
4. **是否需要实船日志比对**:如有海试数据,M6 增加残差分析模块