GL Robotics
首页博客教程Motion Planning Simulator

关于我们

按照主题,分享学习心得。

快速链接

  • 博客
  • 教程
  • 关于我们

联系我们

公众号:哎嗨人生

邮箱:ahrs365@outlook.com

© 2026 GL Robotics. 保留所有权利.

沪ICP备2022016268号-1

    返回教程列表

    AL-iLQR实践指南 2.理解 Bellman 递推和 Riccati 方程

    时空联合规划
    预计阅读时间:11 分钟
    2026年3月25日

    Chapter 2: 有限时域 LQR

    目标:理解 Bellman 递推和 Riccati 方程,实现从"给定控制"到"求解最优控制"的跨越

    代码仓库:https://github.com/my-al-ilqr/al-ilqr-starter

    2.1 从"评估"到"优化"

    在 Chapter 1 中,我们只能做"评估"——给定控制序列,计算轨迹和代价。但我们真正想做的是找到最优的控制序列。

    LQR(Linear Quadratic Regulator,线性二次调节器)是这个问题的线性特例,具有解析解。它是理解 iLQR 的基础。

    2.2 LQR 问题定义

    基础概念

    LQR 处理的是线性动力学 + 二次代价的特殊情况。本文讲解的是参考跟踪(reference-tracking)形式的 LQR:

    min⁡u0,…,uN−112(xN−xref)TQf(xN−xref)+12∑k=0N−1[(xk−xref)TQ(xk−xref)+(uk−uref)TR(uk−uref)] \min_{u_0, \ldots, u_{N-1}} \quad \frac{1}{2} (x_N - x_{\text{ref}})^T Q_f (x_N - x_{\text{ref}}) + \frac{1}{2} \sum_{k=0}^{N-1} \left[ (x_k - x_{\text{ref}})^T Q (x_k - x_{\text{ref}}) + (u_k - u_{\text{ref}})^T R (u_k - u_{\text{ref}}) \right] u0​,…,uN−1​min​21​(xN​−xref​)TQf​(xN​−xref​)+21​k=0∑N−1​[(xk​−xref​)TQ(xk​−xref​)+(uk​−uref​)TR(uk​−uref​)]

    s.t.xk+1=Axk+Buk \text{s.t.} \quad x_{k+1} = A x_k + B u_k s.t.xk+1​=Axk​+Buk​

    其中:

    • A∈Rn×nA \in \mathbb{R}^{n \times n}A∈Rn×n 是状态转移矩阵
    • B∈Rn×mB \in \mathbb{R}^{n \times m}B∈Rn×m 是控制输入矩阵
    • Q⪰0Q \succeq 0Q⪰0 是状态代价矩阵(半正定)
    • R≻0R \succ 0R≻0 是控制代价矩阵(正定)
    • Qf⪰0Q_f \succeq 0Qf​⪰0 是终端代价矩阵
    • xrefx_{\text{ref}}xref​ 是状态参考点(目标状态),urefu_{\text{ref}}uref​ 是控制参考点

    参考跟踪 vs 调节器形式:当 xref=0,uref=0x_{\text{ref}} = 0, u_{\text{ref}} = 0xref​=0,uref​=0 时退化为标准调节器形式。后续推导中,Riccati 递推(求增益 KkK_kKk​)与参考点无关;参考点只影响控制律的应用:uk=uref+Kk(xk−xref)u_k = u_{\text{ref}} + K_k (x_k - x_{\text{ref}})uk​=uref​+Kk​(xk​−xref​)。

    对应代码中的问题定义(include/lqr/finite_horizon_lqr_solver.hpp):

     
    struct FiniteHorizonLQRProblem {
      Matrix A;                    // 状态转移矩阵 (n×n)
      Matrix B;                    // 控制输入矩阵 (n×m)
      Matrix Q;                    // 状态代价矩阵 (n×n)
      Matrix R;                    // 控制代价矩阵 (m×m)
      Matrix Qf;                   // 终端代价矩阵 (n×n)
      Vector state_reference;      // 状态参考点
      Vector control_reference;    // 控制参考点
      int horizon = 0;             // 时域长度 N
    };
     

    我们要找一组控制序列 u0,u1,...,uN−1u₀, u₁, ..., u_{N-1}u0​,u1​,...,uN−1​,使系统从初始状态 x0x₀x0​ 出发,尽量靠近参考点 xrefx_refxr​ef,同时不消耗过多控制能量。

    本步得到:一个 N 步全局优化问题。变量维度很高(n×N + m×N),直接求解不现实。 下一步要做:引入动态规划,把全局问题拆成 N 个单步问题。


    2.3 LQR 动态规划的完整推导

    下图为总览流程图: 下图为核心推导细节,展示 Bellman 方程如何一步步变成 Riccati 递推和控制律

    动态规划的核心思想是:最优策略的子策略也是最优的(最优性原理)。 动态规划的关键是从后往前思考:假设我们已经知道从第k+1k+1k+1 步到终点的最优代价,那么在第 kkk 步该如何选择 uku_kuk​​?

    值函数

    如果我们定义值函数(Value Function)为从第 kkk 步开始到终点的最小代价:

    Vk(xk)=min⁡uk,…,uN−1[12δxNTQfδxN+∑i=kN−112(δxiTQδxi+δuiTRδui)] V_k(x_k) = \min_{u_k, \ldots, u_{N-1}} \left[ \frac{1}{2} δx_N^T Q_f δx_N + \sum_{i=k}^{N-1} \frac{1}{2}(δx_i^T Q δx_i + δu_i^T R δu_i) \right] Vk​(xk​)=uk​,…,uN−1​min​[21​δxNT​Qf​δxN​+i=k∑N−1​21​(δxiT​Qδxi​+δuiT​Rδui​)]

    Bellman方程

    Bellman 方程(最优性原理),把 VkV_kVk​拆成"当前步代价 + 未来最优代价":

    Vk(xk)=min⁡uk[½δxkTQδxk+½δukTRδuk+Vk+1(xk+1)]V_k(x_k) = \min_{u_k} [ ½ δx_kᵀ Q δx_k + ½ δu_kᵀ R δu_k + V_{k+1}(x_{k+1}) ]Vk​(xk​)=uk​min​[½δxkT​Qδxk​+½δukT​Rδuk​+Vk+1​(xk+1​)]

    其中:

    δxk=xk−xref,δuk=uk−uref,xk+1=Axk+Bukδx_k = x_k − x_{ref} , δu_k = u_k − u_{ref} , x_{k+1} = A x_k + B u_kδxk​=xk​−xref​,δuk​=uk​−uref​,xk+1​=Axk​+Buk​

    这就是 Bellman 方程——它把一个NNN步优化问题递归地分解成了一系列单步优化问题。 含义:第 kkk 步的最优代价 = 当前代价 + 从下一状态出发的最优代价。

    本步得到:Bellman 递推结构。NNN 步全局优化 → NNN 个单步 minminmin 问题。 下一步要做:确定 VkV_kVk​ 的具体函数形式,才能真正求解。

    二次型假设

    终端条件(k=Nk = Nk=N):没有后续代价了,只有终端代价:   VN=½(xN−xref)TQf(xN−xref)V_N = ½(x_N − x_{ref})ᵀ Q_f (x_N − x_{ref})VN​=½(xN​−xref​)TQf​(xN​−xref​)    假设每一步的 VkV_kVk​ 都保持二次型:  Vk(xk)=½(xk−xref)TPk(xk−xref)V_k(x_k) = ½ (x_k − x_{ref})ᵀ P_k (x_k − x_{ref})Vk​(xk​)=½(xk​−xref​)TPk​(xk​−xref​)  其中 PkP_kPk​​ 是待求的对称正半定矩阵,终端条件:PN=QfP_N = Q_fPN​=Qf​

    本步得到:值函数的参数化形式。求 VkV_kVk​ 转化为求矩阵 PkP_kPk​。 下一步要做:把假设代入 Bellman 方程,展开并对 uku_kuk​ 求导。

    二次型假设带入Bellman方程

    将Vk+1=½δxk+1TPk+1δxk+1V_{k+1} = ½ δx_{k+1}ᵀ P_{k+1} δx_{k+1}Vk+1​=½δxk+1T​Pk+1​δxk+1​和动力学 δxk+1=Aδxk+Bδukδx_{k+1} = A δx_k + B δu_kδxk+1​=Aδxk​+Bδuk​ 代入 Bellman 方程: (这里有一个重要的注意点:当参考点是系统的平衡点(即 xref=Axref+Burefx_{ref} = A x_{ref} + B u_{ref}xref​=Axref​+Buref​​)时,交叉项消失,递推可以完全用偏差量 δx,δu\delta x, \delta uδx,δu表示。)

    Vk=minδuk½[δxkTQδxk+δukTRδuk+(Aδxk+Bδuk)TPk+1(Aδxk+Bδuk)]V_k = min_{δu_k} ½ [ δx_kᵀ Q δx_k + δu_kᵀ R δu_k + (Aδx_k + Bδu_k)ᵀ P_{k+1} (Aδx_k + Bδu_k) ]Vk​=minδuk​​½[δxkT​Qδxk​+δukT​Rδuk​+(Aδxk​+Bδuk​)TPk+1​(Aδxk​+Bδuk​)]

    这是关于 δukδu_kδuk​ 的 凸二次函数(因为 R≻0R ≻ 0R≻0),对 δukδu_kδuk​ 求导并令其为零:

    ∂/∂(δuk)=Rδuk+BTPk+1(Aδxk+Bδuk)=0∂/∂(δu_k) = R δu_k + Bᵀ P_{k+1} (A δx_k + B δu_k) = 0 ∂/∂(δuk​)=Rδuk​+BTPk+1​(Aδxk​+Bδuk​)=0

    整理:

    (R+BTPk+1B)δuk=−BTPk+1Aδxk(R + Bᵀ P_{k+1} B) δu_k = −Bᵀ P_{k+1} A δx_k(R+BTPk+1​B)δuk​=−BTPk+1​Aδxk​

    本步得到:最优 δukδu_kδuk​ 关于 δxkδx_kδxk​ 的线性方程。 下一步要做:解这个方程,得到反馈增益 KkK_kKk​。

    解出增益与 Riccati 方程

    由于 R≻0R ≻ 0R≻0 且 Pk+1⪰0P_{k+1} ⪰ 0Pk+1​⪰0,矩阵 (R+BTPk+1B)(R + Bᵀ P_{k+1} B)(R+BTPk+1​B) 一定可逆。直接解出增益矩阵: Kk=−(R+BTPk+1B)−1BTPk+1AK_k = −(R + Bᵀ P_{k+1} B)⁻¹ Bᵀ P_{k+1} AKk​=−(R+BTPk+1​B)−1BTPk+1​A 将最优 δuk∗=Kkδxkδu_k* = K_k δx_kδuk​∗=Kk​δxk​ 代回值函数,整理后得到 PkP_kPk​ 关于 Pk+1P_{k+1}Pk+1​ 的递推: 离散Riccati方程:Pk=Q+ATPk+1A−ATPk+1B(R+BTPk+1B)−1BTPk+1A离散 Riccati 方程: P_k = Q + Aᵀ P_{k+1} A − Aᵀ P_{k+1} B (R + Bᵀ P_{k+1} B)⁻¹ Bᵀ P_{k+1} A离散Riccati方程:Pk​=Q+ATPk+1​A−ATPk+1​B(R+BTPk+1​B)−1BTPk+1​A 从 PN=QfP_N = Q_fPN​=Qf​ 开始,逐步算出 PN−1,PN−2,...,P0P_{N-1}, P_{N-2}, ..., P_0PN−1​,PN−2​,...,P0​,同时得到每一步的 KkK_kKk​。

    本步得到:两个核心公式 —— 增益 KkK_kKk​ 和 RiccatiRiccatiRiccati 递推。注意它们只依赖 A,B,Q,RA, B, Q, RA,B,Q,R,与参考点无关。 下一步要做:将增益应用到实际控制中。

    离线阶段:反向递推

    前向执行:实时计算控制量

    反向递推阶段(离线)已经算好了所有 KkK_kKk​。现在正向运行系统,得到最终控制律 : uk∗=uref+Kk(xk−xref)u_k* = u_{ref} + K_k (x_k − x_{ref})uk​∗=uref​+Kk​(xk​−xref​) 每一步只需做一次矩阵乘法,不需要任何数值搜索或迭代优化,非常适合实时控制。


    2.6 代码实现

    Backward Pass:Riccati 递推

    // src/lqr/finite_horizon_lqr_solver.cpp
    void FiniteHorizonLQRSolver::Solve() {
      // Step 1: 终端条件
      riccati_matrices_.back() = problem_.Qf;    // P_N = Q_f
      // Step 2: 从 k=N-1 递推到 k=0
      for (int k = problem_.horizon - 1; k >= 0; --k) {
        const Matrix& P_next = riccati_matrices_[k + 1];          // P_{k+1}
        // S = R + Bᵀ P_{k+1} B
        const Matrix S = problem_.R + problem_.B.transpose() * P_next * problem_.B;
        // K_k = -S⁻¹ Bᵀ P_{k+1} A
        const Matrix rhs = problem_.B.transpose() * P_next * problem_.A;
        feedback_gains_[k] = -S.ldlt().solve(rhs);                // 用 LDLT 分解求解
        // P_k = Q + Aᵀ P_{k+1} (A + B K_k)
        riccati_matrices_[k] =
            problem_.Q + problem_.A.transpose() * P_next * (problem_.A + problem_.B * feedback_gains_[k]);
      }
      is_solved_ = true;
    }
     

    Forward Simulate:闭环仿真

    Trajectory FiniteHorizonLQRSolver::Simulate(const Vector& initial_state) const {
      Trajectory trajectory(problem_.StateDim(), problem_.ControlDim(), problem_.horizon);
      trajectory.State(0) = initial_state;
      for (int k = 0; k < problem_.horizon; ++k) {
        // 反馈控制律: u_k = u_ref + K_k (x_k - x_ref)
        trajectory.Control(k) = Control(trajectory.State(k), k);
        // 线性动力学: x_{k+1} = A x_k + B u_k
        trajectory.State(k + 1) = problem_.A * trajectory.State(k)
                                 + problem_.B * trajectory.Control(k);
      }
      return trajectory;
    }
     
    Vector FiniteHorizonLQRSolver::Control(const Vector& state, int k) const {
      const Vector state_error = state - problem_.state_reference;
      return problem_.control_reference + feedback_gains_[k] * state_error;
    }

    2.7 LQR 与 iLQR 的关系

    LQR 是 iLQR 的"内核"。两者的关键区别:

    特性LQRiLQR
    动力学线性 xk+1=Ax+Bux_{k+1} = Ax + Buxk+1​=Ax+Bu非线性 xk+1=f(x,u)x_{k+1} = f(x,u)xk+1​=f(x,u)
    代价二次任意(用二次近似)
    求解方式一次 backward + forward迭代:多次 backward + forward
    JacobianA,BA, BA,B 已知需要在每次迭代时重新计算

    iLQR 的核心思想:在当前轨迹处将非线性问题局部线性化/二次化,得到一个 LQR 子问题,求解后更新轨迹,如此反复迭代。

    
      iLQR = 迭代地做以下事情:
      ┌──────────────────────────────────────────┐
      │ 1. 在当前轨迹处线性化动力学 → A_k, B_k    │
      │ 2. 在当前轨迹处二次化代价 → Q, R 等       │
      │ 3. 用 LQR 思路求解反馈增益 K_k, d_k       │  ← 这一步和 LQR 几乎一样!
      │ 4. 用增益更新轨迹                         │
      │ 5. 若未收敛,回到 1                       │
      └──────────────────────────────────────────┘
    

    2.8 本章小结

    我们从一个维度很高的全局优化问题出发,通过 Bellman 方程把它拆成 N 个单步问题;然后利用 LQR 的二次型结构,让每一步都有解析解(不用数值搜索);最终反向算完所有增益矩阵后,正向运行时每步只需要一次矩阵乘法就能算出最优控制量。

    核心收获:

    • Backward pass + Forward simulate 的"双向"结构,是后续 iLQR 和 AL-iLQR 的核心骨架
    • LQR 反馈增益 KkK_kKk​ 的求解方式(Riccati 递推),将在 iLQR 中以几乎相同的形式出现