跳转至

控制器

控制器栈负责将高层目标转换为 MuJoCo 演示所需的执行器级命令。就实际阅读体验而言,本地 runner 是理解这条数据流最好的入口,因为它把目标状态、控制器、mixer、动力学以及 MuJoCo actuators 全部串在了同一个文件里。

在包结构层面,具体控制器统一组织在公共接口 ControllerBase 之下。它定义了 PID、几何控制、以及学习式或自适应控制器共用的生命周期与目标管理模式。

flowchart LR
  Target[目标或策略输出] --> Mapping[映射]
  Mapping --> Controller[控制器]
  Controller --> Mixer[Mixer]
  Mixer --> Rotor[旋翼动力学]
  Rotor --> MuJoCo[MuJoCo 执行器]

  Mapping --> TrackController[履带控制器]
  TrackController --> TrackDynamics[履带动力学]
  TrackDynamics --> MuJoCo

端到端控制流程

lav2.controller.run 中的飞行控制循环按如下顺序执行:

  1. 读取 MuJoCo 传感器,获取位姿、速度、姿态和机体系角速度。
  2. 构造 FlightController 所期望的控制器状态向量。
  3. 将目标与状态转换为总推力和机体系力矩。
  4. 通过 Mixer 将该 wrench 分配为旋翼 RPM 命令。
  5. 将旋翼 RPM 命令输入 RotorDynamics
  6. 将得到的推力与扭矩写入 MuJoCo actuators。

履带控制路径与之类似,但会用 TrackControllerTrackDynamics 替代 mixer 加旋翼动力学这一支路。

PID 控制器

lav2.controller.pid 中包含可复用的 PID 基础块,以及两个组合控制器:

飞行控制器

飞行控制器采用级联 PID 结构:

  • 位置环生成速度目标
  • 速度环生成横滚 / 俯仰命令与总推力
  • 姿态环生成角速度目标
  • 角速度环生成机体系力矩
flowchart LR
  TPos[位置目标]
  TVel[速度目标]
  TAtt[姿态目标]
  TRate[角速度目标]
  TThr[总推力目标]

  subgraph Cascade[飞行控制级联]
    direction LR
    Pos[位置环] --> Vel[速度环] --> Att[姿态环] --> Rate[角速度环] --> Mixer[Mixer] --> Rotor[旋翼动力学] --> Act[MuJoCo 执行器]
  end

  TPos --> Pos
  TVel --> Vel
  TAtt --> Att
  TRate --> Rate
  TThr --> Mixer

control_mask 决定了哪些目标通道由外部直接提供,哪些通道则在级联内部生成。这正是同一个控制器能够同时支持位置式与低层控制模式的关键。

lav2.controller.run 中,较低层的飞行模式还会覆盖总推力进入控制栈的方式。对于 cmd_ctattcmd_ctbr,推力相关目标会先通过 apply_thrust_curve(...),再经由 Mixer 直接注入 mixer 输入,而不是由外层的位置环和速度环生成。这也是为什么这些模式表现为“嵌套的姿态 / 角速度控制 + 油门直通”,而不是完整的外环位置控制。

履带控制器

履带控制器工作在平面状态布局 [x, y, yaw, u, v, r] 上,输出左右履带的加速度式命令。由于这一路径当前主要针对平面地面约束建模,而不是完整 6-DoF 飞行约束,因此它的结构会比飞行级联简单得多。

其它控制器家族

包内还提供了建立在 ControllerBase 之上的其它控制器结构:

即使它们内部的控制律不同于 PID 级联,在包级组织方式上仍遵循同一模式。

Mixer 与控制分配

Mixer 仅用于旋翼飞行器路径。它通过求逆一个基于 VehicleParams 派生出的几何分配矩阵,把总推力与横滚 / 俯仰 / 偏航力矩分配到四个旋翼命令上。

Mixer 还承担了与 PX4 对齐的归一化推力转换功能。之所以重要,是因为 PX4 本质上工作在归一化推力 / 力矩风格的输入语义上,而不是直接消费物理量形式的 wrench 命令;因此,LAV2 正是在 mixer 这一层完成“内部物理推力表示”与“PX4 风格归一化命令”之间的转换。

这里有两个需要特别注意的实现细节。

首先,NumPy 与 Torch 版 mixer 目前有意保持了不完全一致的行为。NumPy 版本额外实现了一种分配策略:在发生饱和时优先保留横滚与俯仰控制裕度,再分配偏航。而 Torch 版本则保留了更基础的分配路径,以兼顾计算效率与更通用的 batched 场景。

其次,虽然两个实现都承担“把期望推力与力矩映射为旋翼命令”这一高层职责,但如果你在不同后端之间比较精确的分配行为,应当预期存在这一当前差异。

输出会先在平方 RPM 空间中裁剪,再取平方根。

辅助模块

当你处理的不只是控制律本身时,还有两个辅助模块很值得了解:

  • lav2.controller.utils:提供控制器响应、执行器行为的日志、可视化与数据导出能力。
  • lav2.controller.mapping:负责将策略输出对齐到对应控制环期望的输入形式,这对分层 RL 控制尤其重要,因为不同 RL agent 可能驱动级联中的不同层。

运行时入口

  • lav2.controller.run.mainuv run lav2 背后的 CLI 入口。
  • control_callback 负责在运行时切换飞行模式与履带模式。
  • 飞行与履带两条执行路径都实现于 lav2.controller.run 中,紧接在 control_callback 之后,是理解本地完整数据流的最佳阅读位置。

接下来读什么

当你需要理解本地模拟器或调节控制器增益时,请使用本页。若下一步工作是强化学习训练,或需要大规模 batched 环境,则转到 Isaac Lab 任务

API 交叉引用