Files

285 lines
17 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.
# 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 增加残差分析模块