跳转至

轨迹

LAV2 中的轨迹用于定义时间参数化的参考信号。它位于高层任务意图与实际驱动车辆的控制或策略路径之间,回答的是一个非常基础但又非常关键的问题:在给定时刻 t,系统当前应当跟踪什么目标?

在这个仓库里,轨迹并不被视为控制器逻辑。它不负责决定跟踪误差如何调节,也不承担奖励计算或后端环境结构的定义。它的职责更单一,也更清晰:生成语义稳定的参考状态,使同一类目标信号能够在本地仿真、并行训练后端和评估工作流之间复用。

角色与边界

轨迹的主要作用,是生成与控制栈使用同一套状态语义的参考量。对飞行路径而言,这意味着输出一个 dict,包含 pos(N,3), vel(N,3), acc(N,3), att_euler(N,3), ang_vel(N,3) 五个键,其中 N 是并行环境数量。因此,轨迹层位于控制级联之上,也位于选择参考信号族的任务或脚本之下。

这个边界之所以重要,是因为它把职责清楚地分开了。轨迹描述的是“随时间变化的期望运动”。控制器负责把这个参考量翻译成力、力矩或执行器级命令。任务后端则负责决定何时采样参考、如何把它暴露给策略,以及跟踪效果如何进入奖励或终止条件。只有把这几层保持分离,轨迹实现才能保持可复用,而不会逐渐演化成控制器逻辑或任务逻辑的隐式副本。

flowchart LR
  T[时间参数] --> Traj[轨迹]
  Traj --> Ref[Dict 参考目标]
  Ref --> Ctrl[控制器或策略路径]
  Ctrl --> Act[执行器与动力学]
  Act --> State[观测状态]

模块组织

LAV2 轨迹实现位于 lav2.trajectories 下,为后端无关的 Array API 类。遗留的 NumPy 和 Torch 实现保留在 lav2.trajectories.numpylav2.trajectories.torch 下,用作性能基准参考。

BaseTrajectory 定义了统一接口,包含批量原语和后端解析(backend/xp/device/num_envs)。SpatialTrajectory 在此基础上引入了广播到形状 (num_envs, 3) 的世界坐标系 center 锚点。

参考量语义

轨迹目标的组装逻辑主要集中在 BaseTrajectory.build_target 中。一个具体轨迹通常先计算位置、速度和加速度,再把这些基础量拼装成完整目标字典。偏航角既可以根据平面速度自动生成,也可以固定为常数;横滚、俯仰和机体系角速度则直接来自轨迹配置,不从闭环跟踪结果中反推。

这意味着轨迹层已经携带了一部分姿态参考语义,但它依然不是控制器。它只是以控制栈能够理解的形式提供期望的姿态相关量,真正如何去调节这些量,仍然属于控制器或策略的职责。

另一个很有用的设计细节是,航向生成逻辑在不同轨迹形状之间共享。当 yaw_from_velocity 打开时,航向会跟随平面速度方向,偏航角速度参考则由速度和加速度共同计算;当它关闭时,轨迹则可以保持固定航向。这让螺旋、矩形、双纽线等不同轨迹族在航向语义上保持一致。

典型轨迹类型

最简单的一类内置参考是 HoverStepTrajectory。它生成分段常值的位置与偏航目标,因此特别适合观察瞬态行为。超调、稳定时间、饱和以及模式切换等问题,在阶跃类目标下往往最容易暴露,因为期望状态本身就是有意不连续的。

RectangleTrajectory 更适合用于观察长直线匀速段与尖角转向之间的切换行为。它能够比较直接地暴露方向变化、控制裕度以及航向更新过程中的问题,因此在对比连续平滑曲线与具有明显几何拐点的路径时非常有用。

HelixTrajectory 引入了水平与垂向耦合运动。当需要观察控制器或策略在平移、航向对齐与高度变化同时存在时是否仍然稳定,螺旋轨迹通常是很好的参考。可选的垂向振荡也使它比单纯平面圆轨迹更有信息量。

LemniscateTrajectoryLissajousTrajectory 更适合覆盖更广的工作空间。双纽线会反复穿过中心区域,因此有助于观察系统在曲率变化和自交运动附近的表现。Lissajous 轨迹则更一般,可以用连续、平滑且周期性的方式覆盖更大的三维范围,适合做更密集的参考激励,而非单一机动动作验证。

把这些轨迹放在一起看,它们服务的是不同的工程目的。阶跃类目标更适合看瞬态,几何闭环轨迹更适合看持续跟踪,复杂周期曲线更适合暴露多轴耦合效应。相比某条轨迹的具体数学形式,这种“它更适合拿来验证什么”的区分往往更重要。

轨迹如何进入系统

在本地路径中,轨迹会随着仿真时间被采样,随后把生成出的目标传给 MuJoCo runner 所期望的控制器接口。在训练后端中,类似的参考量也可能由命令管理器或后端专用任务项持有,但概念角色是一致的:它仍然是在生成与控制栈对齐的目标信号。

flowchart TD
  A[轨迹类] --> B[在时刻 t 采样]
  B --> C[参考目标]
  C --> D[本地 runner 或任务后端]
  D --> E[控制器或策略]
  E --> F[执行与动力学]

这也是轨迹与任务边界应当保持清晰的地方。任务定义的是参考信号如何调度、如何随机化、如何进入奖励以及如何暴露给学习代码;轨迹定义的是参考信号本身属于哪一类运动原语。只有把这两部分分开,同一个运动原语才更容易在本地验证、控制器评估和强化学习环境中复用,而不需要重复实现。

扩展约定

新增轨迹时,最重要的要求是保持输出语义稳定。新的轨迹类仍应输出与现有轨迹族相同含义的 dict 目标,而不应在采样函数里混入控制器启发式、后端专用奖励假设或本地可视化逻辑。

第二个规则是面向 Array API 顶层。一份实现覆盖所有后端——无需单独的 NumPy 或 Torch 副本。

第三个要求,是继续把时间作为显式的组织变量。这个包里的轨迹是时间参数化的参考生成器,而不是会在内部悄悄改变任务逻辑的状态机。只有这样,它们在更大的控制与训练工作流里才能维持稳定角色,也更容易被单独理解与复用。

API 交叉引用