动力学
LAV2 面向陆空两栖与飞行平台提供统一的动力学参数与接口框架。其实现将动力学组织为一个共享参数对象,以及若干与执行形式相关的模型实现,使得本地 MuJoCo 运行器与 GPU/任务端后端能够在相同的物理常数和接口约定上保持一致。
已知建模限制
这里的模块拆分主要服务于实现组织与数值计算,并不意味着旋翼与接触动力学在物理上已经被完全解耦。例如升力对接触力的影响等耦合关系,尚未进一步建模。
机体参数
VehicleParams 是平台最核心的参数接口。它将机体描述划分为:
- 环境参数
- 机身参数
- 螺旋桨参数
- 地面驱动参数
- 与 PX4 对齐的参数
其中一部分值来自直接配置,另一部分则会在 __post_init__ 中派生出来,例如推力与反扭矩系数、默认初始 RPM,以及悬停油门相关量。因此在实际使用中,VehicleParams 不仅定义平台的原始常数,也定义了下游动力学与控制器真正消费的量。
需要质量、惯量、仿真步长、旋翼系数或驱动几何参数时,应优先从 VehicleParams 出发,而不是把相关字面量散落在各个模块中。
在模块结构层面,显式动力学实现统一组织在 DynamicsBase 这一公共接口之下。地面接触由轮组几何与仿真器接触约束表示,不再使用独立的解析履带外力模块。
时间尺度:sim_dt 与 step_dt
一旦同一套动力学被放到本地单速率模拟器之外使用,这两个时间参数就会变得非常重要。sim_dt 表示执行器与物理积分步长,而 step_dt 表示控制器更新步长。
在带 decimation 的框架中,例如 Isaac Lab,这两者往往并不相同,因为物理引擎的步进频率通常高于控制策略或命令更新频率。当后续引入高层与低层策略异步运行时,这种区分也同样重要。把这两个字段统一保存在 VehicleParams 中,可以避免将频率假设隐含在单个模块内部。
旋翼动力学
RotorDynamics 将每个旋翼的 RPM 命令转换为一个批量 (N, 8) 输出数组:
- 每个环境的前 4 个量:推力
- 每个环境的后 4 个量:反扭矩
它的更新规则遵循标准的旋翼模型结构。命令转速不会被瞬时施加,而是先经过滤波与速率限制;随后根据旋翼速度与电机角加速度计算推力与反扭矩:
其中,\(\omega_i\) 表示旋翼转速,\(f_i\) 表示推力,\(\tau_i\) 表示反扭矩,\(c_T\) 与\(c_M\) 分别是推力与扭矩系数,\(d_i \in \{+1, -1\}\) 通过 VehicleParams.spin_dir 编码旋翼旋向;约定 +1 为顺时针,-1 为逆时针。实际滤波更新中,还会使用独立的上升/下降时间常数,并对 RPM 变化率做显式裁剪。
要让这个模型真正有意义,它必须和真实平台参数保持一致,尤其包括:
- 初始旋翼转速
- 电机惯量与时间常数
- 推力与扭矩系数
- 最大 RPM
- 旋翼旋向
地面驱动执行器
地面平台使用关节化轮组与仿真器接触模型。在 MuJoCo 中,LAV2 将左右输出轴速度目标分别发送给每侧唯一的主动关节,再通过 equality 约束同步主动轮与承重轮组;ATMO 同样每侧只使用一个闭环速度伺服器,并用 equality 约束表示前后轮壳之间的同步带传动。
Isaac Lab 沿用相同的二维侧速度目标和“每侧一个主动关节”契约。当前 LAV2 与 ATMO USD 仍需后续补齐与 MJCF 一致的关节拓扑和机械耦合;不能通过向从动关节重复下发 ActionTerm 目标来替代资产级耦合。
这样可以明确分离控制器、actuator 与接触职责:DifferentialDriveController 负责底盘级命令分配,平台适配层把每侧目标映射到物理关节,速度伺服器按配置的增益与力矩上限输出,物理引擎负责求解轮地作用力。当命令是轮速时,速度伺服增益是闭环跟踪增益,不能用开环 DC 电机的转矩—转速斜率代替。
状态与命令约定
所有控制器与轨迹接口使用字典形式的状态与目标对象。所有状态数组均为批量形式,带有一个前导环境维度 N(num_envs)。整个控制栈使用的字典键如下:
| 键 | 形状 | 单位 | 描述 |
|---|---|---|---|
pos |
(N, 3) |
m | 世界坐标系位置 |
vel |
(N, 3) |
m/s | 世界坐标系速度 |
vel_b |
(N, 3) |
m/s | 机体系速度 |
att_euler |
(N, 3) |
rad | 横滚、俯仰、偏航(XYZ 内旋) |
att_quat |
(N, 4) |
— | 四元数(xyzw) |
att_rotmat |
(N, 9) |
— | 旋转矩阵(行主序展平) |
ang_vel |
(N, 3) |
rad/s | 机体系角速度 |
thrust |
(N, 1) |
N | 总推力目标 |
飞行状态字典包含 pos、vel、att_euler、att_quat、att_rotmat 与 ang_vel。地面控制器状态字典包含 pos、att_euler、vel_b 与 ang_vel(注意此处使用 vel_b 而非 vel)。
飞行与地面控制器都遵循 ControllerBase 的更新签名:update(target: dict, state: dict) -> ArrayLike。control_mask 字典控制哪些目标通道由外部提供、哪些由级联内部生成。
当 N = 1(单环境)时,批量形状退化为 (1, 3)、(1, 4) 等。lav2/dynamics/numpy/ 下的遗留 NumPy 实现使用非批量形状(如 (3,)、(4,)),且不与 Array API 兼容。
明确上述字典约定之后,再去阅读本地模拟器、控制器栈和各类任务封装会容易很多。
并行后端一致性
lav2/dynamics/ 下的顶层模块是后端无关的 Array API 实现——通过 self._xp 分发,单一代码库即可服务于 NumPy、Torch、JAX 和 CuPy。numpy/ 与 torch/ 子包是保留用于基准测试的遗留参考实现;新增动力学模块应以 Array API 顶层为目标。
API 交叉引用
- 共享参数:VehicleParams
- 旋翼模型:RotorDynamics
- 差速控制器:DifferentialDriveController