4. 决策规划框架

各位同学,今天我们聊点实在的。决策规划这个事儿,说白了就是让车知道“接下来该干嘛”。你想想看,一个无人车在复杂路况里跑,它得同时处理好几层问题:要去哪儿?怎么走?方向盘打多少?

我刚开始做这个方向时,也想过“能不能一个算法搞定所有”。后来发现,不行。为什么?因为不同层次的问题,对实时性、精度、抽象程度的要求完全不同。所以,分层架构就成了行业共识。

4.1 分层架构:任务规划、行为规划、运动规划

这套架构,我习惯把它比作一个公司的三层管理:

  • 任务规划(Route Planning):相当于CEO,定大方向。从A到B,走哪条路,经过哪些路口。它不关心具体怎么开,只关心路径。
  • 行为规划(Behavior Planning):相当于部门经理,做决策。比如“前方有车,我要变道”、“路口要减速让行”。它输出的是驾驶行为。
  • 运动规划(Motion Planning):相当于执行者,算轨迹。具体到每一帧的方向盘角度、油门开度。它输出的是平滑的轨迹曲线。

我在项目中遇到过一个问题:任务规划给的路径太粗,导致行为规划频繁切换。比如明明可以直行,任务规划却建议绕个小弯。嗯,后来我们加了一层路径平滑,才解决。

核心要点:每一层只关注自己该做的事。任务规划别管方向盘,运动规划别管目的地。各司其职,系统才稳定。

下面这张图,是我自己画的架构图。你看一眼就明白了:

任务规划(Route Planning) 输入:地图、起点、终点 → 输出:全局路径(道路级) 行为规划(Behavior Planning) 输入:全局路径、感知信息 → 输出:驾驶行为(变道、跟车、让行) 运动规划(Motion Planning) 输入:驾驶行为、车辆状态 → 输出:轨迹(位置、速度、加速度) 反馈(执行结果)

4.2 状态机与行为树

行为规划这块,最经典的做法就是状态机。说白了,就是给车定义好几种状态:直行、变道、左转、右转、停车。然后根据条件跳转。

我早期做的一个项目,用的就是有限状态机。代码大概长这样:

// 状态机示例(伪代码)
enum State {
  CRUISE,      // 巡航
  FOLLOW,      // 跟车
  LANE_CHANGE, // 变道
  STOP         // 停车
}

State currentState = CRUISE;

void updateState(PerceptionData data) {
  switch(currentState) {
    case CRUISE:
      if (data.frontCarDistance < 30m) {
        currentState = FOLLOW;
      }
      break;
    case FOLLOW:
      if (data.frontCarDistance > 50m) {
        currentState = CRUISE;
      }
      if (data.laneChangeAvailable) {
        currentState = LANE_CHANGE;
      }
      break;
    // ... 其他状态
  }
}

状态机的好处是简单、直观。但问题也很明显——状态多了以后,跳转逻辑会变得一团乱麻。我曾经维护过一个有30多个状态的状态机,每次加一个新功能都提心吊胆。

后来,行为树(Behavior Tree)开始流行。它用树形结构组织行为,每个节点要么是“选择节点”(挑一个子节点执行),要么是“序列节点”(按顺序执行)。

我的建议:如果你的场景比较固定(比如园区低速车),状态机完全够用。但如果是开放道路、场景多变,行为树更灵活。我个人现在更倾向行为树,因为它好扩展、好调试。

举个例子,行为树处理“路口通行”的逻辑:

// 行为树节点示例
SequenceNode("通过路口") {
  ConditionNode("是否有红绿灯") {
    if (有红绿灯) {
      ActionNode("根据红绿灯决策");
    } else {
      ActionNode("根据路权规则决策");
    }
  }
  ActionNode("减速观察");
  ActionNode("执行通过");
}

4.3 基于优化的方法

说到运动规划,就不得不提基于优化的方法。说白了,就是把轨迹规划变成一个数学优化问题——在满足约束的前提下,找一个最优解。

常见的优化目标包括:

  • 平滑性(加速度变化率最小)
  • 安全性(与障碍物距离最大)
  • 舒适性(横向加速度最小)
  • 效率(行驶时间最短)

约束条件就更多了:

  • 车辆动力学约束(最大转向角、最大加速度)
  • 道路边界约束(不能压线、不能上路沿)
  • 障碍物约束(不能碰撞)
  • 交通规则约束(红灯停、限速)

我常用的一个框架是二次规划(QP)。它把问题写成:

minimize:  0.5 * x^T * H * x + f^T * x
subject to: A * x <= b
            l <= x <= u

其中x是轨迹参数(比如每个时间点的位置、速度),H矩阵控制平滑性,约束矩阵A控制安全边界。

注意:基于优化的方法虽然数学上漂亮,但实际落地时坑很多。我曾经遇到过优化不收敛的情况,车在原地打转。后来发现是约束条件写得太紧,给了一点松弛空间就好了。

还有一种方法是模型预测控制(MPC)。它滚动优化,每帧都重新算一遍。实时性要求高,但效果确实好。我建议你在做高速场景时优先考虑MPC。

方法 优点 缺点 适用场景
状态机 简单、直观、调试方便 状态多时维护困难 低速、固定场景
行为树 扩展性好、可复用 学习成本稍高 开放道路、复杂场景
二次规划(QP) 数学严谨、轨迹平滑 可能不收敛、计算量大 结构化道路
模型预测控制(MPC) 实时性好、能处理约束 模型依赖性强 高速、动态场景

最后说一句,没有银弹。我在实际项目中,往往是混合使用——行为规划用行为树,运动规划用MPC。你想想看,这样既保证了决策的灵活性,又保证了轨迹的平滑性。

嗯,这一章的内容就到这儿。记住,分层架构的核心是“各司其职”,别让运动规划去操心目的地,也别让任务规划去操心方向盘。

本章小结:

  • 分层架构:任务规划(路径)→ 行为规划(决策)→ 运动规划(轨迹)
  • 状态机适合简单场景,行为树适合复杂场景
  • 基于优化的方法(QP、MPC)能生成平滑轨迹,但要注意收敛性和实时性

可可精品资料库