最优化理论与自动驾驶(十一):基于iLQR的自动驾驶轨迹跟踪算法(c++和python版本)

最优化理论与自动驾驶(四):iLQR原理、公式及代码演示

之前的章节我们介绍过,iLQR(迭代线性二次调节器)是一种用于求解非线性系统最优控制最优控制最优控制和规划问题的算法。本章节介绍采用iLQR算法对设定的自动驾驶轨迹进行跟踪,与第十章节纯跟踪算法采用同样跟踪轨迹,同时,我们仅对控制量的上下边界进行约束,使用简单的投影法进行约束(更详细的约束参考第九章 CILQR约束条件下的ILQR求解)。其实,iLQR可以直接进行轨迹规划,主要做法是将障碍物或者边界约束通过增广拉格朗日法将原始问题的约束条件通过拉格朗日乘子和惩罚项结合到代价函数中,逐步逼近最优解,这个将在后续章节进行讨论。

1. 问题定义

假设给定一个目标轨迹(x_{ref}, u_{ref}),其中x_{ref}是状态轨迹,u_{ref}是控制输入,任务是找到一组控制输入u_k使得车辆从初始状态出发,最小化实际轨迹与目标轨迹之间的偏差。

(1) 状态方程

车辆的运动可以通过车辆动力学模型表示,通常有以下几种模型:

  • 简化运动学模型

    x_{k+1} = f(x_k, u_k)

    其中x_k是车辆的状态,u_k是控制输入。

根据参考轨迹,将非线性系统模型在当前状态和控制输入附近进行线性化:

f(x_k, u_k) \approx A_k \Delta x_k + B_k \Delta u_k + c_k

其中A_k = \frac{\partial f}{\partial x}B_k = \frac{\partial f}{\partial u}是对状态和控制的线性化,\Delta x_k = x_k - x_{ref}\Delta u_k = u_k - u_{ref}​。

(2) 代价函数

定义一个二次型代价函数,用于衡量实际轨迹与目标轨迹的偏差:

J = \sum_{k=0}^{N-1} \left( (x_k - x_{ref})^T Q (x_k - x_{ref}) + (u_k - u_{ref})^T R (u_k - u_{ref}) \right) + (x_N - x_{ref})^T Q_f (x_N - x_{ref})

其中QRQ_f分别是状态、控制输入和最终状态的权重矩阵。

(3) 反向递推

利用动态规划方法,从最终时刻 N开始,向前递推计算值函数的梯度和Hessian矩阵:

V_x = \frac{\partial J}{\partial x}, \quad V_{xx} = \frac{\partial^2 J}{\partial x^2}

同时计算控制增量的最优更新策略:

\Delta u_k = K_k \Delta x_k + d_k

其中K_k是控制增量的反馈增益,d_k是前馈控制增量。

(4) 前向传播

基于反向递推得到的最优控制策略,在给定初始状态下,通过前向传播计算新的状态和控制轨迹,更新参考轨迹:

x_{k+1} = f(x_k, u_k)

重复步骤(1)至(4)直到收敛,得到最优控制序列。

2. 示例代码

import numpy as np
import math
import matplotlib.pyplot as plt
import imageio# 车辆模型
class Vehicle:def __init__(self, x=0.0, y=0.0, theta=0.0, v=0.0):self.x = xself.y = yself.theta = theta  # 航向角self.v = v          # 速度def update(self, a, omega, dt):"""更新车辆状态a: 加速度omega: 角速度dt: 时间步长"""self.x += self.v * np.cos(self.theta) * dtself.y += self.v * np.sin(self.theta) * dtself.theta += omega * dtself.v += a * dt# 轨迹
class Trajectory:def __init__(self):self.cx = np.linspace(0, 50, 500)self.cy = [np.sin(ix / 5.0) * ix / 2.0 for ix in self.cx]self.theta = [np.arctan2(self.cy[i+1] - self.cy[i], self.cx[i+1] - self.cx[i]) if i < len(self.cx)-1 else 0.0 for i in range(len(self.cx))]self.v = np.full_like(self.cx, 3.0)  # 目标速度为3 m/sdef get_reference(self, index):"""获取参考轨迹点"""return np.array([self.cx[index], self.cy[index], self.theta[index], self.v[index]])# iLQR控制器
class iLQRController:def __init__(self, N=50, max_iter=10, dt=0.1):self.N = N  # 控制时域长度self.max_iter = max_iter  # 最大迭代次数self.dt = dt  # 时间步长self.Q = np.diag([1.0, 1.0, 0.5, 0.1])  # 状态权重矩阵self.R = np.diag([0.1, 0.1])  # 控制权重矩阵self.Qf = self.Q * 10  # 终端状态权重矩阵def ilqr(self, vehicle, trajectory, index):"""使用iLQR计算最优控制序列"""# 初始化状态和控制序列x_dim = 4  # 状态维度 [x, y, theta, v]u_dim = 2  # 控制维度 [a, omega]xs = np.zeros((self.N + 1, x_dim))us = np.zeros((self.N, u_dim))# 初始状态xs[0] = np.array([vehicle.x, vehicle.y, vehicle.theta, vehicle.v])# 初始猜测控制序列(全零)us = np.zeros((self.N, u_dim))for iteration in range(self.max_iter):# 前向传播,计算状态轨迹for k in range(self.N):xs[k+1] = self.dynamics(xs[k], us[k], self.dt)# 计算代价函数梯度和Hessian矩阵Vx = self.Qf @ (xs[-1] - trajectory.get_reference(index + self.N))Vxx = self.Qfk_list = []K_list = []for k in reversed(range(self.N)):xk = xs[k]uk = us[k]x_ref = trajectory.get_reference(index + k)# 计算状态和控制的偏导数fx, fu = self.linearize_dynamics(xk, uk, self.dt)lx = self.Q @ (xk - x_ref)lu = self.R @ uklxx = self.Qluu = self.Rlux = np.zeros((u_dim, x_dim))# 计算Q函数的二次近似Qx = lx + fx.T @ VxQu = lu + fu.T @ VxQxx = lxx + fx.T @ Vxx @ fxQuu = luu + fu.T @ Vxx @ fuQux = lux + fu.T @ Vxx @ fx# 计算控制增量Quu_inv = np.linalg.inv(Quu + np.eye(u_dim) * 1e-6)  # 加小值防止矩阵奇异k = -Quu_inv @ QuK = -Quu_inv @ Qux# 更新V函数Vx = Qx + K.T @ Quu @ k + K.T @ Qu + Qux.T @ kVxx = Qxx + K.T @ Quu @ K + K.T @ Qux + Qux.T @ K# 存储k和Kk_list.insert(0, k)K_list.insert(0, K)# 更新控制序列并前向模拟x_new = np.copy(xs[0])xs_new = [x_new]us_new = []for k in range(self.N):du = k_list[k] + K_list[k] @ (x_new - xs[k])us_new.append(us[k] + du)x_new = self.dynamics(x_new, us_new[-1], self.dt)xs_new.append(x_new)xs = np.array(xs_new)us = np.array(us_new)# 判断收敛性cost = self.compute_total_cost(xs, us, trajectory, index)print(f"Iteration {iteration}, Cost: {cost}")if cost < 1e-6:breakreturn us[0]  # 返回当前时刻的最优控制def dynamics(self, x, u, dt):"""动力学模型"""x_next = np.zeros_like(x)x_next[0] = x[0] + x[3] * np.cos(x[2]) * dt  # xx_next[1] = x[1] + x[3] * np.sin(x[2]) * dt  # yx_next[2] = x[2] + u[1] * dt                 # thetax_next[3] = x[3] + u[0] * dt                 # vreturn x_nextdef linearize_dynamics(self, x, u, dt):"""线性化动力学模型,返回状态和控制的雅可比矩阵"""fx = np.eye(4)fx[0, 2] = -x[3] * np.sin(x[2]) * dtfx[0, 3] = np.cos(x[2]) * dtfx[1, 2] = x[3] * np.cos(x[2]) * dtfx[1, 3] = np.sin(x[2]) * dtfx[2, 2] = 1.0fx[3, 3] = 1.0fu = np.zeros((4, 2))fu[2, 1] = dt  # theta 对 omega 的偏导fu[3, 0] = dt  # v 对 a 的偏导return fx, fudef compute_total_cost(self, xs, us, trajectory, index):"""计算总的代价函数"""cost = 0.0for k in range(self.N):xk = xs[k]uk = us[k]x_ref = trajectory.get_reference(index + k)dx = xk - x_refcost += dx.T @ self.Q @ dx + uk.T @ self.R @ uk# 终端代价dx = xs[-1] - trajectory.get_reference(index + self.N)cost += dx.T @ self.Qf @ dxreturn cost# 主函数
def main():vehicle = Vehicle()trajectory = Trajectory()controller = iLQRController(N=50, max_iter=10, dt=0.1)dt = 0.1x_history = []y_history = []total_time = len(trajectory.cx) - controller.N - 1# 创建图形fig, ax = plt.subplots()frames = []for t in range(total_time):# 获取当前最优控制u_opt = controller.ilqr(vehicle, trajectory, t)# 更新车辆状态vehicle.update(u_opt[0], u_opt[1], dt)# 记录轨迹x_history.append(vehicle.x)y_history.append(vehicle.y)# 绘制ax.cla()ax.plot(trajectory.cx, trajectory.cy, "-r", label="Reference Trajectory")ax.plot(x_history, y_history, "-b", label="Vehicle Trajectory")ax.set_xlim(0, 50)ax.set_ylim(-20, 25)ax.set_title(f"iLQR Trajectory Tracking - Step {t}")ax.set_xlabel("x [m]")ax.set_ylabel("y [m]")ax.grid(True)# 渲染当前帧fig.canvas.draw()image = np.frombuffer(fig.canvas.tostring_rgb(), dtype='uint8').reshape(fig.canvas.get_width_height()[::-1] + (3,))frames.append(image)# 实时显示plt.pause(0.001)# 保存为GIFimageio.mimsave('ilqr_trajectory_tracking.gif', frames, fps=10)plt.show()if __name__ == '__main__':main()

2.1. 车辆模型 (Vehicle 类)

车辆模型采用一个简单的运动学模型,其中更新车辆的状态包括:

位置 (x, y)
航向角 (theta)
速度 (v)
通过给定加速度 (a) 和角速度 (omega),每个时间步长内,车辆的状态都会更新。

class Vehicle:def __init__(self, x=0.0, y=0.0, theta=0.0, v=0.0):self.x = xself.y = yself.theta = theta  # 航向角self.v = v          # 速度def update(self, a, omega, dt):"""更新车辆状态a: 加速度omega: 角速度dt: 时间步长"""self.x += self.v * np.cos(self.theta) * dtself.y += self.v * np.sin(self.theta) * dtself.theta += omega * dtself.v += a * dt

2. 轨迹 (Trajectory 类) 

轨迹类生成了一条目标轨迹,cx 和 cy 分别是参考轨迹的 x 和 y 轴坐标。车辆的目标是跟随这条正弦曲线,并在参考轨迹的每个点上都有相应的目标航向角 (theta) 和速度 (v)。

# 轨迹
class Trajectory:def __init__(self):self.cx = np.linspace(0, 50, 500)self.cy = [np.sin(ix / 5.0) * ix / 2.0 for ix in self.cx]self.theta = [np.arctan2(self.cy[i+1] - self.cy[i], self.cx[i+1] - self.cx[i]) if i < len(self.cx)-1 else 0.0 for i in range(len(self.cx))]self.v = np.full_like(self.cx, 3.0)  # 目标速度为3 m/sdef get_reference(self, index):"""获取参考轨迹点"""return np.array([self.cx[index], self.cy[index], self.theta[index], self.v[index]])

3. iLQR 控制器 (iLQRController 类) 

iLQR 控制器的主要职责是计算从当前时刻开始的最优控制序列,使得车辆的状态逼近目标轨迹。以下是关键步骤:

初始化:定义状态和控制权重矩阵 (Q, R, Qf) 以惩罚偏离目标状态和过大的控制输入。
前向传播:给定初始控制输入,模拟车辆状态随时间的演化。
反向递推:通过动态规划的方法,逐步计算代价函数的梯度和 Hessian,并优化控制策略。
线性化动力学:在当前状态下线性化系统的动力学方程,计算状态和控制的雅可比矩阵。
更新控制序列:通过更新控制增量,生成新的控制序列并前向传播,直到算法收敛。

# iLQR控制器
class iLQRController:def __init__(self, N=50, max_iter=10, dt=0.1):self.N = N  # 控制时域长度self.max_iter = max_iter  # 最大迭代次数self.dt = dt  # 时间步长self.Q = np.diag([1.0, 1.0, 0.5, 0.1])  # 状态权重矩阵self.R = np.diag([0.1, 0.1])  # 控制权重矩阵self.Qf = self.Q * 10  # 终端状态权重矩阵def ilqr(self, vehicle, trajectory, index):"""使用iLQR计算最优控制序列"""# 初始化状态和控制序列x_dim = 4  # 状态维度 [x, y, theta, v]u_dim = 2  # 控制维度 [a, omega]xs = np.zeros((self.N + 1, x_dim))us = np.zeros((self.N, u_dim))# 初始状态xs[0] = np.array([vehicle.x, vehicle.y, vehicle.theta, vehicle.v])# 初始猜测控制序列(全零)us = np.zeros((self.N, u_dim))for iteration in range(self.max_iter):# 前向传播,计算状态轨迹for k in range(self.N):xs[k+1] = self.dynamics(xs[k], us[k], self.dt)# 计算代价函数梯度和Hessian矩阵Vx = self.Qf @ (xs[-1] - trajectory.get_reference(index + self.N))Vxx = self.Qfk_list = []K_list = []for k in reversed(range(self.N)):xk = xs[k]uk = us[k]x_ref = trajectory.get_reference(index + k)# 计算状态和控制的偏导数fx, fu = self.linearize_dynamics(xk, uk, self.dt)lx = self.Q @ (xk - x_ref)lu = self.R @ uklxx = self.Qluu = self.Rlux = np.zeros((u_dim, x_dim))# 计算Q函数的二次近似Qx = lx + fx.T @ VxQu = lu + fu.T @ VxQxx = lxx + fx.T @ Vxx @ fxQuu = luu + fu.T @ Vxx @ fuQux = lux + fu.T @ Vxx @ fx# 计算控制增量Quu_inv = np.linalg.inv(Quu + np.eye(u_dim) * 1e-6)  # 加小值防止矩阵奇异k = -Quu_inv @ QuK = -Quu_inv @ Qux# 更新V函数Vx = Qx + K.T @ Quu @ k + K.T @ Qu + Qux.T @ kVxx = Qxx + K.T @ Quu @ K + K.T @ Qux + Qux.T @ K# 存储k和Kk_list.insert(0, k)K_list.insert(0, K)# 更新控制序列并前向模拟x_new = np.copy(xs[0])xs_new = [x_new]us_new = []for k in range(self.N):du = k_list[k] + K_list[k] @ (x_new - xs[k])us_new.append(us[k] + du)x_new = self.dynamics(x_new, us_new[-1], self.dt)xs_new.append(x_new)xs = np.array(xs_new)us = np.array(us_new)# 判断收敛性cost = self.compute_total_cost(xs, us, trajectory, index)print(f"Iteration {iteration}, Cost: {cost}")if cost < 1e-6:breakreturn us[0]  # 返回当前时刻的最优控制def dynamics(self, x, u, dt):"""动力学模型"""x_next = np.zeros_like(x)x_next[0] = x[0] + x[3] * np.cos(x[2]) * dt  # xx_next[1] = x[1] + x[3] * np.sin(x[2]) * dt  # yx_next[2] = x[2] + u[1] * dt                 # thetax_next[3] = x[3] + u[0] * dt                 # vreturn x_nextdef linearize_dynamics(self, x, u, dt):"""线性化动力学模型,返回状态和控制的雅可比矩阵"""fx = np.eye(4)fx[0, 2] = -x[3] * np.sin(x[2]) * dtfx[0, 3] = np.cos(x[2]) * dtfx[1, 2] = x[3] * np.cos(x[2]) * dtfx[1, 3] = np.sin(x[2]) * dtfx[2, 2] = 1.0fx[3, 3] = 1.0fu = np.zeros((4, 2))fu[2, 1] = dt  # theta 对 omega 的偏导fu[3, 0] = dt  # v 对 a 的偏导return fx, fudef compute_total_cost(self, xs, us, trajectory, index):"""计算总的代价函数"""cost = 0.0for k in range(self.N):xk = xs[k]uk = us[k]x_ref = trajectory.get_reference(index + k)dx = xk - x_refcost += dx.T @ self.Q @ dx + uk.T @ self.R @ uk# 终端代价dx = xs[-1] - trajectory.get_reference(index + self.N)cost += dx.T @ self.Qf @ dxreturn cost

4. 主循环 (main 函数)

主函数执行轨迹跟踪的模拟过程。每一步:

调用 iLQR 控制器生成最优控制输入。
根据控制输入更新车辆状态。
绘制当前的车辆轨迹与参考轨迹,并生成一帧图像。
最终,所有帧被保存为 GIF 文件,展示整个轨迹跟踪过程。

5. 执行结果

6. c++版本

在实际的工程开发中,一般采用c++代码进行开发。为了方便应用,将上述代码转为C++,涉及的矩阵运算主要采用eigen库(参考 C++教程(一):超详细的C++矩阵操作和运算(附实例代码,与python对比))。同时为了方便展示动态运行过程,采用了python的matplotlib的c++库matplotlibcpp,也非常容易使用,直接include头文件即可。C++代码如下:

#include <iostream>
#include <vector>
#include <cmath>
#include <Eigen/Dense>
#include "matplotlibcpp.h"namespace plt = matplotlibcpp;
using Eigen::MatrixXd;
using Eigen::VectorXd;// 车辆模型类
class Vehicle {
public:double x, y, theta, v;// 车辆构造函数,初始化车辆的状态Vehicle(double x_init = 0.0, double y_init = 0.0, double theta_init = 0.0, double v_init = 0.0): x(x_init), y(y_init), theta(theta_init), v(v_init) {}// 更新车辆状态,a为加速度,omega为角速度,dt为时间步长void update(double a, double omega, double dt) {x += v * cos(theta) * dt;    // 更新x坐标y += v * sin(theta) * dt;    // 更新y坐标theta += omega * dt;         // 更新航向角thetav += a * dt;                 // 更新速度v}
};// 轨迹类,用于存储参考轨迹信息
class Trajectory {
public:std::vector<double> cx, cy, theta, v;// 轨迹构造函数,初始化参考轨迹Trajectory() {// 生成参考轨迹的x和y坐标for (double i = 0; i < 50; i += 0.1) {cx.push_back(i);cy.push_back(sin(i / 5.0) * i / 2.0);}// 计算每个轨迹点的航向角thetafor (size_t i = 0; i < cx.size() - 1; ++i) {theta.push_back(atan2(cy[i+1] - cy[i], cx[i+1] - cx[i]));}theta.push_back(0.0);  // 最后一个点的theta设置为0v.assign(cx.size(), 3.0);  // 设置所有点的目标速度为3 m/s}// 获取指定索引处的参考状态向量[x, y, theta, v]VectorXd get_reference(size_t index) const {VectorXd ref(4);ref << cx[index], cy[index], theta[index], v[index];return ref;}
};// iLQR(迭代线性二次调节器)控制器类
class iLQRController {
public:int N;             // 控制步数int max_iter;      // 最大迭代次数double dt;         // 时间步长MatrixXd Q, R, Qf; // 代价函数的权重矩阵// 控制器构造函数iLQRController(int N_input = 50, int max_iter_input = 10, double dt_input = 0.1): N(N_input), max_iter(max_iter_input), dt(dt_input) {// 初始化状态代价矩阵Q,控制代价矩阵R,终端状态代价矩阵QfQ = MatrixXd::Zero(4, 4);Q(0, 0) = 1.0; Q(1, 1) = 1.0; Q(2, 2) = 0.5; Q(3, 3) = 0.1;R = MatrixXd::Identity(2, 2) * 0.1;Qf = Q * 10.0;}// iLQR算法的实现,返回当前时刻的最优控制输入VectorXd ilqr(Vehicle &vehicle, const Trajectory &trajectory, size_t index) {int x_dim = 4;  // 状态维度 [x, y, theta, v]int u_dim = 2;  // 控制维度 [a, omega]std::vector<VectorXd> xs(N + 1, VectorXd::Zero(x_dim));  // 状态序列std::vector<VectorXd> us(N, VectorXd::Zero(u_dim));      // 控制序列// 初始化状态xs[0] << vehicle.x, vehicle.y, vehicle.theta, vehicle.v;// 迭代更新控制输入和状态for (int iter = 0; iter < max_iter; ++iter) {// 前向传播,基于当前控制序列预测状态序列for (int i = 0; i < N; ++i) {xs[i + 1] = dynamics(xs[i], us[i], dt);}// 反向传播,更新控制增量和反馈矩阵VectorXd Vx = Qf * (xs[N] - trajectory.get_reference(index + N));MatrixXd Vxx = Qf;std::vector<VectorXd> k_control_list(N, VectorXd::Zero(u_dim));  // 控制增量std::vector<MatrixXd> K_feedback_list(N, MatrixXd::Zero(u_dim, x_dim));  // 反馈矩阵for (int i = N - 1; i >= 0; --i) {VectorXd x_ref = trajectory.get_reference(index + i);std::pair<MatrixXd, MatrixXd> linearized = linearize_dynamics(xs[i], us[i], dt);MatrixXd fx = linearized.first;MatrixXd fu = linearized.second;// 计算代价梯度和Hessian矩阵VectorXd lx = Q * (xs[i] - x_ref);VectorXd lu = R * us[i];MatrixXd lxx = Q;MatrixXd luu = R;MatrixXd lux = MatrixXd::Zero(u_dim, x_dim);// 计算Q函数的二次近似VectorXd Qx = lx + fx.transpose() * Vx;VectorXd Qu = lu + fu.transpose() * Vx;MatrixXd Qxx = lxx + fx.transpose() * Vxx * fx;MatrixXd Quu = luu + fu.transpose() * Vxx * fu;MatrixXd Qux = lux + fu.transpose() * Vxx * fx;// 计算控制增量和反馈矩阵MatrixXd Quu_inv = Quu.inverse();VectorXd k_control = -Quu_inv * Qu;MatrixXd K_feedback = -Quu_inv * Qux;// 更新价值函数Vx = Qx + K_feedback.transpose() * Quu * k_control + K_feedback.transpose() * Qu + Qux.transpose() * k_control;Vxx = Qxx + K_feedback.transpose() * Quu * K_feedback + K_feedback.transpose() * Qux + Qux.transpose() * K_feedback;k_control_list[i] = k_control;K_feedback_list[i] = K_feedback;}// 更新控制序列并进行前向模拟std::vector<VectorXd> xs_new(N + 1, xs[0]);std::vector<VectorXd> us_new;for (int i = 0; i < N; ++i) {VectorXd du = k_control_list[i] + K_feedback_list[i] * (xs_new[i] - xs[i]);us_new.push_back(us[i] + du);xs_new[i + 1] = dynamics(xs_new[i], us_new.back(), dt);}xs = xs_new;us = us_new;// 判断是否收敛double cost = compute_total_cost(xs, us, trajectory, index);std::cout << "Iteration " << iter << ", Cost: " << cost << std::endl;if (cost < 1e-6) {break;}}return us[0];  // 返回当前时刻的最优控制输入}// 车辆动力学模型VectorXd dynamics(const VectorXd &x, const VectorXd &u, double dt) {VectorXd x_next = x;x_next[0] += x[3] * cos(x[2]) * dt;  // 更新x坐标x_next[1] += x[3] * sin(x[2]) * dt;  // 更新y坐标x_next[2] += u[1] * dt;              // 更新thetax_next[3] += u[0] * dt;              // 更新速度vreturn x_next;}// 线性化车辆动力学模型std::pair<MatrixXd, MatrixXd> linearize_dynamics(const VectorXd &x, const VectorXd &u, double dt) {MatrixXd fx = MatrixXd::Identity(4, 4);fx(0, 2) = -x[3] * sin(x[2]) * dt;fx(0, 3) = cos(x[2]) * dt;fx(1, 2) = x[3] * cos(x[2]) * dt;fx(1, 3) = sin(x[2]) * dt;MatrixXd fu = MatrixXd::Zero(4, 2);fu(2, 1) = dt;fu(3, 0) = dt;return {fx, fu};}// 计算总成本double compute_total_cost(const std::vector<VectorXd> &xs, const std::vector<VectorXd> &us, const Trajectory &trajectory, size_t index) {double cost = 0.0;for (int i = 0; i < N; ++i) {VectorXd dx = xs[i] - trajectory.get_reference(index + i);cost += (dx.transpose() * Q * dx)(0, 0) + (us[i].transpose() * R * us[i])(0, 0);}VectorXd dx_terminal = xs[N] - trajectory.get_reference(index + N);cost += (dx_terminal.transpose() * Qf * dx_terminal)(0, 0);return cost;}
};// 主函数
int main() {Vehicle vehicle;  // 初始化车辆Trajectory trajectory;  // 初始化轨迹iLQRController controller(10, 10, 0.1);  // 初始化iLQR控制器double dt = 0.1;std::vector<double> x_history, y_history;  // 记录车辆轨迹for (size_t t = 0; t < trajectory.cx.size() - controller.N - 1; ++t) {VectorXd u_opt = controller.ilqr(vehicle, trajectory, t);  // 获取最优控制输入vehicle.update(u_opt[0], u_opt[1], dt);  // 更新车辆状态x_history.push_back(vehicle.x);  // 记录x坐标y_history.push_back(vehicle.y);  // 记录y坐标// 绘制车辆轨迹和参考轨迹plt::clf();plt::named_plot("Reference Trajectory", trajectory.cx, trajectory.cy, "-r");plt::named_plot("Vehicle Trajectory", x_history, y_history, "-b");plt::legend();plt::xlim(0, 50);plt::ylim(-20, 25);plt::title("iLQR Trajectory Tracking");plt::xlabel("x [m]");plt::ylabel("y [m]");plt::grid(true);plt::pause(0.001);  // 短暂暂停以动态展示}plt::show();  // 展示最终图形return 0;
}

 6. 后续优化

加入障碍物回避:在代价函数中加入障碍物相关的约束项,直接进行规控一体优化;

采用全DDP算法:考虑系统动态中的二阶项,通过全DDP算法提升优化精度;

噪声处理:考虑车辆运动中的过程噪声和观测噪声,用iLQG使得算法更加鲁棒。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/54497.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分析redis实现分布式锁的思路

文章目录 1、基于redis实现分布式锁&#xff1a;利用key的唯一性1.1、独占排他1.2、死锁问题1.2.1、redis客户端程序获取了锁之后&#xff0c;服务器立马宕机&#xff0c;就会导致死锁。1.2.2、不可重入&#xff1a;可重入 1.3、原子性&#xff1a;加锁和过期之间&#xff1a;s…

深入剖析Docker容器安全:挑战与应对策略

随着容器技术的广泛应用&#xff0c;Docker已成为现代应用开发和部署的核心工具。它通过轻量级虚拟化技术实现应用的隔离与封装&#xff0c;提高了资源利用率。然而&#xff0c;随着Docker的流行&#xff0c;其安全问题也成为关注焦点。容器化技术虽然提供了良好的资源隔离&…

4.C_数据结构_队列

概述 什么是队列&#xff1a; 队列是限定在两端进行插入操作和删除操作的线性表。具有先入先出(FIFO)的特点 相关名词&#xff1a; 队尾&#xff1a;写入数据的一段队头&#xff1a;读取数据的一段空队&#xff1a;队列中没有数据&#xff0c;队头指针 队尾指针满队&#…

FPGA与Matlab图像处理之直方图均衡化

文章目录 一、什么是直方图?二、什么是直方图均衡化&#xff1f;三、Matlab实现直方图均衡化的步骤第一步&#xff1a; 彩色图像转成灰度图像第二步&#xff1a;提取亮度通道的直方图第三步&#xff1a;累计亮度通道的像素值频率第四步&#xff1a; 映射到新的灰度值 四、Veri…

嵌入式 开发技巧和经验分享

文章目录 前言嵌入式 开发技巧和经验分享目录1.1嵌入式 系统的 定义1.2 嵌入式 操作系统的介绍1.3 嵌入式 开发环境1.4 编译工具链和优化1.5 嵌入式系统软件开发1.6 嵌入式SDK开发2.1选择移植的系统-FreeRtos2.2FreeRtos 移植步骤2.3 系统移植之中断处理2.4系统移植之内存管理2…

【java面经】Redis速记

目录 基本概念 string hash list set zset 常见问题及解决 缓存穿透 缓存击穿 缓存雪崩 Redis内存管理策略 noeviction allkeys-lru allkeys-random volatile-random volatile-ttl Redis持久化机制 RDB快照 AOF追加文件 Redis多线程特性 Redis应用场景 缓…

【医学半监督】置信度指导遮蔽学习的半监督医学图像分割

摘要: 半监督学习(Semi-supervised learning)旨在利用少数标记数据和多数未标记数据训练出高性能模型。现有方法大多采用预测任务机制,在一致性或伪标签的约束下获得精确的分割图,但该机制通常无法克服确认偏差。针对这一问题,本文提出了一种用于半监督医学图像分割的新…

【梯度下降|链式法则】卷积神经网络中的参数是如何传输和更新的?

【梯度下降|链式法则】卷积神经网络中的参数是如何传输和更新的&#xff1f; 【梯度下降|链式法则】卷积神经网络中的参数是如何传输和更新的&#xff1f; 文章目录 【梯度下降|链式法则】卷积神经网络中的参数是如何传输和更新的&#xff1f;1. 什么是梯度&#xff1f;2.梯度…

2024-04-23 人工智能增强天基通信和传感

砺道智库2024-04-23 11:18 北京 据国家防务网4月19日报道&#xff0c;随着商业卫星、军事星座及其所有数据在太空中流动的数量不断增加&#xff0c;政府和行业运营商表示&#xff0c;他们正在寻求人工智能来帮助他们处理日益复杂的任务。 人工智能软件使用户能够在轨道上改变航…

饲料颗粒机全套设备有哪些机器组成

饲料颗粒机全套设备通常包括原料粉碎、混合机、制粒机、冷却器、筛分机、包装机以及配套的电气控制等多个部分组成&#xff1a;1、粉碎机&#xff1a;将各种饲料原料进行清理、去杂、破碎等预处理&#xff0c;确保原料的纯净度和适宜粒度&#xff0c;为后续加工做准备。2、混合…

【永磁同步电机(PMSM)】 5. PMSM 的仿真模型

【永磁同步电机&#xff08;PMSM&#xff09;】 5. PMSM 的仿真模型 1. 基于 Simulink 的仿真模型1.1 PMSM 的数学模型1.2 Simulink 仿真模型1.3 模块封装&#xff08;mask&#xff09;1.4 三相PMSM矢量控制仿真模型 2. Simscape 的 PMSM 模块2.1 PMSM 模块的配置2.2 PMSM 模块…

数据结构与算法学习day22-回溯算法-分割回文串、复原IP地址、子集

一、分割回文串 1.题目 131. 分割回文串 - 力扣&#xff08;LeetCode&#xff09; 2.思路 分割回文串可以抽象为一棵树形结构。 递归用来纵向遍历&#xff0c;for循环用来横向遍历&#xff0c;切割线&#xff08;就是图中的红线&#xff09;切割到字符串的结尾位置&#xf…

WIFI路由器的套杆天线简谈

❝本次推文简单介绍下WIFI路由器的套杆天线。 路由器天线 路由器在这个万物互联的时代&#xff0c;想必大家对其都不陌生。随着科技的发展&#xff0c;常用的路由器上的天线也越来越多&#xff0c;那么问题来了&#xff1a;天线越多&#xff0c;信号越好吗&#xff1f;路由器…

浅谈Spring Cloud:认识微服务

SpringCloud就是分布式微服务架构的一站式解决方案&#xff0c;是微服务架构落地的多种技术的集合。 目录 微服务远程调用 Eureka注册中心 搭建Eureka Server 注册组件 服务拉取 当各种各样的服务越来越多&#xff0c;拆分的也越来越细&#xff0c;此时就会出现一个服务集…

计算机毕业设计 社区医疗服务系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

MySQL高阶1919-兴趣相同的朋友

题目 请写一段SQL查询获取到兴趣相同的朋友。用户 x 和 用户 y 是兴趣相同的朋友&#xff0c;需满足下述条件&#xff1a; 用户 x 和 y 是朋友&#xff0c;并且用户 x and y 在同一天内听过相同的歌曲&#xff0c;且数量大于等于三首. 结果表 无需排序 。注意&#xff1a;返…

常见排序(C语言版)

1.排序的概念及其应用 1.1排序的概念 排序&#xff1a;​ 在计算机科学与数学中&#xff0c;一个排序算法&#xff08;英语&#xff1a;Sorting algorithm&#xff09;是一种能将一串资料依照特定排序方式排列的算法。 稳定性&#xff1a;假定在待排序的记录序列中&#xff…

聚观早报 | 小米三折叠手机专利曝光;李斌谈合肥投资蔚来

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 9月20日消息 小米三折叠手机专利曝光 李斌谈合肥投资蔚来 索尼PS5 Pro包装亮相 新一代Spectacles AR眼镜发布 通…

《AI系统:原理与架构》于华为HC大会2024正式发布

2024年9月21日&#xff0c;《AI系统&#xff1a;原理与架构》新书发布会在上海世博馆华为HC大会顺利举办。本书由华为昇腾技术专家、B站AI科普博主ZOMI酱和哈工大软件学院副院长苏统华教授联合编写&#xff0c;是领域内AI系统方面填补空白的重磅之作。 发布会上&#xff0c;《A…

Spring:项目中的统一异常处理和自定义异常

介绍异常的处理方式。在项目中&#xff0c;都会进行自定义异常&#xff0c;并且都是需要配合统一结果返回进行使用。 1.背景引入 &#xff08;1&#xff09;背景介绍 为什么要处理异常&#xff1f;如果不处理项目中的异常信息&#xff0c;前端访问我们后端就是显示访问失败的…