美食家大橙子 发表于 2025-1-1 16:34:14

主动驾驶控制与规划——Project 4: MPC车辆控制

零、使命介绍

补全carla-ros-bridge/src/ros-bridge/carla_shenlan_projects/carla_shenlan_mpc_controller/src/mpc_controller.cpp中动力学模型和代价函数构造部分,实现车辆MPC控制。
一、情况设置

使用如下命令安装CppAD
sudo apt install cppad
ipopt的安装参考Linux | Ubuntu 20.04安装ipopt和cppAD | 安装全流程+报错解决,使用方法二源码安装即可。
CppAD库的使用可以参考CppAD优化问题求解
二、算法原理

本次使用的线性化模型与上一篇博客主动驾驶控制与规划——Project 3: LQR车辆横向控制的相同。使用欧拉前向法离散化,有如下的等式束缚:
                                                                                           x                                        (                                        k                                        +                                        1                                        )                                                                                                                     =                                        x                                        (                                        k                                        )                                        +                                                       v                                           x                                                      (                                        k                                        )                                        cos                                        ⁡                                        ψ                                        (                                        k                                        )                                        Δ                                        t                                        −                                                       v                                           y                                                      (                                        k                                        )                                        sin                                        ⁡                                        ψ                                        (                                        k                                        )                                        Δ                                        t                                                                                                                            y                                        (                                        k                                        +                                        1                                        )                                                                                                                     =                                        y                                        (                                        k                                        )                                        +                                                       v                                           y                                                      (                                        k                                        )                                        sin                                        ⁡                                        ψ                                        (                                        k                                        )                                        Δ                                        t                                        +                                                       v                                           y                                                      (                                        k                                        )                                        cos                                        ⁡                                        ψ                                        (                                        k                                        )                                        Δ                                        t                                                                                                                            ψ                                        (                                        k                                        +                                        1                                        )                                                                                                                     =                                        ψ                                        (                                        k                                        )                                        +                                        r                                        (                                        k                                        )                                        Δ                                        t                                                                                                                                           v                                           x                                                      (                                        k                                        +                                        1                                        )                                                                                                                     =                                                       v                                           x                                                      (                                        k                                        )                                        +                                                       a                                           x                                                      (                                        k                                        )                                        Δ                                        t                                                                                                                                           a                                           y                                                      (                                        k                                        )                                                                                                                     =                                        −                                                                                        c                                                 f                                                            +                                                               c                                                 r                                                                                          m                                                               v                                                 x                                                            (                                              k                                              )                                                                                    v                                           y                                                      (                                        k                                        )                                        +                                                       (                                                                                              l                                                    r                                                                                    c                                                    r                                                                  −                                                                   l                                                    f                                                                                    c                                                    f                                                                                                m                                                                   v                                                    x                                                                  (                                                 k                                                 )                                                                        −                                                         v                                              x                                                          (                                           k                                           )                                           )                                                      r                                        (                                        k                                        )                                                                                                                                           v                                           y                                                      (                                        k                                        +                                        1                                        )                                                                                                                     =                                                       v                                           y                                                      (                                        k                                        )                                        +                                                       a                                           y                                                      (                                        k                                        )                                        Δ                                        t                                                                                                                            α                                        (                                        k                                        )                                                                                                                     =                                                                                        l                                                 r                                                                               c                                                 r                                                            −                                                               l                                                 f                                                                               c                                                 f                                                                                                         I                                                 z                                                                               v                                                 x                                                            (                                              k                                              )                                                                                    v                                           y                                                      (                                        k                                        )                                        −                                                                                        l                                                 f                                                 2                                                                               c                                                 f                                                            +                                                               l                                                 r                                                 2                                                                               c                                                 r                                                                                                         I                                                 z                                                                               v                                                 x                                                            (                                              k                                              )                                                                     r                                        (                                        k                                        )                                                                                                                            r                                        (                                        k                                        +                                        1                                        )                                                                                                                     =                                        r                                        (                                        k                                        )                                        +                                        α                                        (                                        k                                        )                                        Δ                                        t                                                                              \begin{aligned} x(k+1) &= x(k) + v_x(k)\cos \psi(k) \Delta t - v_y(k) \sin \psi(k)\Delta t\\ y(k+1) &= y(k) + v_y(k)\sin\psi(k)\Delta t + v_y(k)\cos\psi(k)\Delta t \\ \psi(k+1) &= \psi(k)+r(k)\Delta t \\ v_x(k+1) &= v_x(k) + a_x(k)\Delta t \\ a_y(k) &= -\frac{c_f + c_r}{mv_x(k)} v_y(k) + \left(\frac{l_r c_r - l_f c_f}{m v_x(k)} - v_x(k)\right) r(k) \\ v_y(k+1) &= v_y(k) + a_y(k) \Delta t \\ \alpha(k) &= \frac{l_r c_r - l_f c_f}{I_z v_x(k)} v_y(k) - \frac{l_f^2c_f + l_r^2c_r}{I_z v_x(k)} r(k) \\ r(k+1)&= r(k) + \alpha(k)\Delta t\\ \end{aligned}                     x(k+1)y(k+1)ψ(k+1)vx​(k+1)ay​(k)vy​(k+1)α(k)r(k+1)​=x(k)+vx​(k)cosψ(k)Δt−vy​(k)sinψ(k)Δt=y(k)+vy​(k)sinψ(k)Δt+vy​(k)cosψ(k)Δt=ψ(k)+r(k)Δt=vx​(k)+ax​(k)Δt=−mvx​(k)cf​+cr​​vy​(k)+(mvx​(k)lr​cr​−lf​cf​​−vx​(k))r(k)=vy​(k)+ay​(k)Δt=Iz​vx​(k)lr​cr​−lf​cf​​vy​(k)−Iz​vx​(k)lf2​cf​+lr2​cr​​r(k)=r(k)+α(k)Δt​
其中                                 x                         (                         k                         )                              x(k)                  x(k)是                                 k                              k                  k时刻车辆在世界系下的                                 x                              x                  x坐标;                                 y                         (                         k                         )                              y(k)                  y(k)是                                 k                              k                  k时刻车辆在世界系下的                                 y                              y                  y坐标;                                             v                            x                                       v_x                  vx​是车辆纵向速率;                                             v                            y                                       v_y                  vy​是车辆横向速率;                                 ψ                              \psi                  ψ是偏航角;                                 r                              r                  r是偏航角速率;                                             a                            y                                       a_y                  ay​是车辆横向加速率;                                 α                              \alpha                  α是偏航角加速率;                                 Δ                         t                              \Delta t                  Δt是猜测的时间步长。其他车辆参数寄义可以参考上一期博客主动驾驶控制与规划——Project 3: LQR车辆横向控制。
除上述等式束缚以外,为了使求解速率加快,增长如下的束缚条件令
思量三个方面的代价函数:
三、代码实现

构造函数,初始化状态、目标状态、权重等。
FG_eval::FG_eval(const Eigen::VectorXd &state, VectorXd coeffs, const double &target_v, const int &cte_weight, const int &epsi_weight, const int &v_weight, const int &steer_actuator_cost_weight, const int &acc_actuator_cost_weight, const int &change_steer_cost_weight,
               const int &change_accel_cost_weight, const int &mpc_prediction_horizon_length, const int &mpc_control_horizon_length, const double &mpc_control_step_length, const double &kinamatic_para_Lf, const double &a_lateral, const double &old_steer_value, const double &old_throttle_value,
               const double &steer_ratio) {
    this->steer_ratio = steer_ratio;
    this->coeffs = coeffs;
    this->ref_v = target_v;
    this->cte_weight = cte_weight;
    this->epsi_weight = epsi_weight;
    this->v_weight = v_weight;
    this->steer_actuator_cost_weight_fg = steer_actuator_cost_weight;
    this->acc_actuator_cost_weight_fg = acc_actuator_cost_weight;
    this->change_steer_cost_weight = change_steer_cost_weight;
    this->change_accel_cost_weight = change_accel_cost_weight;
    this->Np = mpc_prediction_horizon_length;
    this->Nc = mpc_control_horizon_length;
    this->dt = mpc_control_step_length;
    this->Lf = kinamatic_para_Lf;
    this->a_lateral = a_lateral;
    /*Indexes on the 1-D vector for readability, These indexes are used for "vars"*/
    this->x_start = 0;
    this->y_start = x_start + Np;
    this->psi_start = y_start + Np;
    this->v_longitudinal_start = psi_start + Np;
    this->v_lateral_start = v_longitudinal_start + Np;
    this->yaw_rate_start = v_lateral_start + Np;
    this->cte_start = yaw_rate_start + Np;
    this->epsi_start = cte_start + Np;
    this->front_wheel_angle_start = epsi_start + Np;
    this->longitudinal_acceleration_start = front_wheel_angle_start + Nc;
    //控制时域长度为25的时候,控制增量一共有24个,第一个时刻点控制量与控制增量相同
    // this->front_wheel_angle_increment_start = epsi_start + Np;
    // this->longitudinal_acceleration_increment_start = front_wheel_angle_increment_start + Nc - 1;

    this->old_steer_value = old_steer_value;
    this->old_throttle_value = old_throttle_value;

    /* Explicitly gather state values for readability */
    this->x = state;
    this->y = state;
    this->psi = state;
    this->v_longitudinal = state;
    this->v_lateral = state;
    this->yaw_rate = state;
    this->cte = state;
    this->epsi = state;
}
FG_eval::operator(),定义MPC的目标函数和束缚条件
void FG_eval::operator()(ADvector &fg, ADvector &vars) {
    // 部分代码已经给出,请同学们补全
    fg = 0;    // 0 is the index at which Ipopt expects fg to store the cost value,
    /* TODO: Objective term 1: Keep close to reference values.*/
    for (size_t t = 0; t < Np; t++) {
      fg += cte_weight * CppAD::pow(vars - ref_cte, 2);
      fg += epsi_weight * CppAD::pow(vars - ref_epsi, 2);
      // AD<double> speed = CppAD::sqrt(vars * vars + vars * vars);
      // std::cout << "ref_v: " << ref_v << std::endl;
      fg += v_weight * CppAD::pow(vars - ref_v, 2);
    }
    /* TODO: Objective term 2: Avoid to actuate as much as possible, minimize the use of actuators.*/
    for (size_t t = 0; t < Nc; t++) {
      fg += steer_actuator_cost_weight_fg * CppAD::pow(vars, 2);
      fg += acc_actuator_cost_weight_fg * CppAD::pow(vars, 2);
    }
    /* TODO: Objective term 3: Enforce actuators smoothness in change, minimize the value gap between sequential actuation.*/
    for (size_t t = 0; t < Nc - 1; t++) {
      fg += change_steer_cost_weight * CppAD::pow(vars - vars, 2);
      fg += change_accel_cost_weight * CppAD::pow(vars - vars, 2);
    }

    /* Initial constraints, initialize the model to the initial state*/
    fg = vars;
    fg = vars;
    fg = vars;
    fg = vars;
    fg = vars;
    fg = vars;
    fg = vars;
    fg = vars;

    for (size_t t = 1; t < Np; t++)    // 预测模型
    {
      // Values at time (t),第一次进入该循环的时候,x_0...传入的是给MPC的系统状态的真实值,作为MPC求解的初始条件.
      AD<double> x_0 = vars;
      AD<double> y_0 = vars;
      AD<double> psi_0 = vars;
      AD<double> v_longitudinal_0 = vars + 0.00001;
      AD<double> v_lateral_0 = vars;
      AD<double> yaw_rate_0 = vars;
      AD<double> cte_0 = vars;
      AD<double> epsi_0 = vars;

      // Values at time (t+1)
      AD<double> x_1 = vars;
      AD<double> y_1 = vars;
      AD<double> psi_1 = vars;
      AD<double> v_longitudinal_1 = vars + 0.00001;
      AD<double> v_lateral_1 = vars;
      AD<double> yaw_rate_1 = vars;
      AD<double> cte_1 = vars;
      AD<double> epsi_1 = vars;

      // Only consider the actuation at time t.
      AD<double> front_wheel_angle_0;
      AD<double> longitudinal_acceleration_0;

      front_wheel_angle_0 = vars;
      longitudinal_acceleration_0 = vars;

      // reference path
      AD<double> f_0 = coeffs + coeffs * x_0 + coeffs * CppAD::pow(x_0, 2) + coeffs * CppAD::pow(x_0, 3) + coeffs * CppAD::pow(x_0, 4) + coeffs * CppAD::pow(x_0, 5);    // + coeffs * CppAD::pow(x_0, 6);

      // reference psi: can be calculated as the tangential angle of the polynomial f evaluated at x_0
      AD<double> psi_des_0 = CppAD::atan(1 * coeffs + 2 * coeffs * x_0 + 3 * coeffs * CppAD::pow(x_0, 2) + 4 * coeffs * CppAD::pow(x_0, 3) + 5 * coeffs * CppAD::pow(x_0, 4));    // + 6 * coeffs * CppAD::pow(x_0, 5));

      // TODO: 补全车辆动力学模型,作为MPC的等式约束条件,车辆动力学模型需要注意参数的正方向的定义
      /*The idea here is to constraint this value to be 0.*/
      /* 全局坐标系 */
      fg = x_1 - (x_0 + (v_longitudinal_0 * CppAD::cos(psi_0) - v_lateral_0 * CppAD::sin(psi_0)) * dt);
      fg = y_1 - (y_0 + (v_longitudinal_0 * CppAD::sin(psi_0) + v_lateral_0 * CppAD::cos(psi_0)) * dt);

      /* 航向角变化 */
      fg = psi_1 - (psi_0 + yaw_rate_0 * dt);

      /* 车辆纵向速度 */
      fg = v_longitudinal_1 - (v_longitudinal_0 + longitudinal_acceleration_0 * dt);

      /* 车辆侧向速度 */
      // 注意这里front_wheel_angle_0符号和第四章推导中定义的delta方向相反
      AD<double> a_lateral = -2 * (Cf + Cr) / (m * v_longitudinal_0) * v_lateral_0 + (2 * (lr * Cr - lf * Cf) / (m * v_longitudinal_0) - v_longitudinal_0) * yaw_rate_0 - 2 * Cf / m * front_wheel_angle_0;
      fg = v_lateral_1 - (v_lateral_0 + a_lateral * dt);

      /* 车辆横摆角速度 */
      AD<double> yaw_acceleration = 2 * (lr * Cr - lf * Cf) / (I * v_longitudinal_0) * v_lateral_0 - 2 * (lf * lf * Cf + lr * lr * Cr) / (I * v_longitudinal_0) * psi_0 - 2 * lf * Cf / I * front_wheel_angle_0;
      fg = yaw_rate_1 - (yaw_rate_0 + yaw_acceleration * dt);

      /* 横向位置跟踪误差 */
      fg = cte_1 - (f_0 - y_0 + v_longitudinal_0 * CppAD::tan(epsi_0) * dt);
      /* 航向跟踪误差 */
      fg = epsi_1 - (psi_0 - psi_des_0 - v_longitudinal_0 * (front_wheel_angle_0 / 1) / Lf * dt);
    }
}
mpc_controller::Solve求解MPC优化问题,返回最优控制量以及猜测的状态轨迹。
std::vector<double> mpc_controller::Solve(const Eigen::VectorXd &state, const Eigen::VectorXd &coeffs, const double &target_v, const int &cte_weight, const int &epsi_weight, const int &v_weight, const int &steer_actuator_cost_weight, const int &acc_actuator_cost_weight,
                                          const int &change_steer_cost_weight, const int &change_accel_cost_weight,
                                          //   const int &mpc_prediction_horizon_length,
                                          const int &mpc_control_horizon_length, const double &mpc_control_step_length, const double &kinamatic_para_Lf, const double &a_lateral, const double &old_steer_value, const double &old_throttle_value, const double &steer_ratio) {
    this->Nc = mpc_control_horizon_length;
    this->Np = Nc + 1;

    this->x_start = 0;
    this->y_start = x_start + Np;
    this->psi_start = y_start + Np;
    this->v_longitudinal_start = psi_start + Np;
    this->v_lateral_start = v_longitudinal_start + Np;
    this->yaw_rate_start = v_lateral_start + Np;
    this->cte_start = yaw_rate_start + Np;
    this->epsi_start = cte_start + Np;
    this->front_wheel_angle_start = epsi_start + Np;
    this->longitudinal_acceleration_start = front_wheel_angle_start + Nc;    //控制时域长度为25的时候,控制量一共有24个。
    // this->front_wheel_angle_increment_start = epsi_start + Np;
    // this->longitudinal_acceleration_increment_start = front_wheel_angle_increment_start + Nc - 1;

    this->a_lateral = a_lateral;
    bool ok = true;

    typedef CPPAD_TESTVECTOR(double) Dvector;

    /* Explicitly gather state values for readability */
    double x = state;
    double y = state;
    double psi = state;
    double v_longitudinal = state;
    double v_lateral = state;
    double yaw_rate = state;
    double cte = state;
    double epsi = state;

    /* Set the number of model variables (includes both states and inputs). */
    /* 系统状态量 + 系统控制增量 */
    size_t n_vars = Np * 8 + Nc * 2;

    /* Set the number of contraints */
    size_t n_constraints = Np * 8;

    /* Initialize all of independent variables to zero. */
    Dvector vars(n_vars);
    for (size_t i = 0; i < n_vars; i++) {
      vars = 0.0;
    }
    // Set the initial variable values**初始化变量及变量上下限**
    vars = x;
    vars = y;
    vars = psi;
    vars = v_longitudinal;
    vars = v_lateral;
    vars = yaw_rate;
    vars = cte;
    vars = epsi;

    Dvector vars_lower_bounds(n_vars);
    Dvector vars_upper_bounds(n_vars);

    /* Set limits for non-actuators (avoid numerical issues during optimization). */
    for (size_t i = 0; i < front_wheel_angle_start; i++) {
      vars_lower_bounds = -std::numeric_limits<float>::max();
      vars_upper_bounds = +std::numeric_limits<float>::max();
    }
    /* Set upper and lower constraints for steering. */
    double max_degree = 24;
    double max_radians = max_degree * M_PI / 180;
    for (size_t i = front_wheel_angle_start; i < longitudinal_acceleration_start; i++) {
      vars_lower_bounds = -max_radians;
      vars_upper_bounds = +max_radians;
    }

    /* Set uppper and lower constraints for acceleration. */
    double max_acceleration_value = 1.0;
    for (size_t i = longitudinal_acceleration_start; i < n_vars; i++) {
      vars_lower_bounds = -max_acceleration_value;
      vars_upper_bounds = +max_acceleration_value;
    }

    /* Initialize to zero lower and upper limits for the constraints*/
    Dvector constraints_lower_bounds(n_constraints);
    Dvector constraints_upper_bounds(n_constraints);
    for (size_t i = 0; i < n_constraints; i++) {
      constraints_lower_bounds = 0;
      constraints_upper_bounds = 0;
    }
    /* Force the solver to start from current state in optimization space. */
    /* 约束条件的形式为 [x(0); x(1) = f(x(0)); ... x(N) = f(x(N-1)); , 每一个约束的第一项其实就是系统当前状态,所以直接约束该量的第一项。
       不能直接给状态 vars 的第一项赋值来限制求解起点,因为状态和控制量理论上都是自由的,所以这里通过设置约束条件第一项的方式来指定优化求解起点,从而加速求解。*/
    constraints_lower_bounds = x;
    constraints_lower_bounds = y;
    constraints_lower_bounds = psi;
    constraints_lower_bounds = v_longitudinal;
    constraints_lower_bounds = v_lateral;
    constraints_lower_bounds = yaw_rate;
    constraints_lower_bounds = cte;
    constraints_lower_bounds = epsi;

    constraints_upper_bounds = x;
    constraints_upper_bounds = y;
    constraints_upper_bounds = psi;
    constraints_upper_bounds = v_longitudinal;
    constraints_upper_bounds = v_lateral;
    constraints_upper_bounds = yaw_rate;
    constraints_upper_bounds = cte;
    constraints_upper_bounds = epsi;
    /* Object that computes objective and constraints. */
    FG_eval fg_eval(state, coeffs, target_v, cte_weight, epsi_weight, v_weight, steer_actuator_cost_weight, acc_actuator_cost_weight, change_steer_cost_weight, change_accel_cost_weight, Np, Nc, mpc_control_step_length, kinamatic_para_Lf, a_lateral, old_steer_value, old_throttle_value, steer_ratio);
    /* NOTE: You don't have to worry about these options. options for IPOPT solver. */
    std::string options;
    /* Uncomment this if you'd like more print information. */
    options += "Integer print_level0\n";
    /* NOTE: Setting sparse to true allows the solver to take advantage
       of sparse routines, this makes the computation MUCH FASTER. If you can
       uncomment 1 of these and see if it makes a difference or not but if you
       uncomment both the computation time should go up in orders of magnitude. */
    options += "Sparsetrue      forward\n";
    options += "Sparsetrue      reverse\n";
    /* NOTE: Currently the solver has a maximum time limit of 0.5 seconds. */
    /* Change this as you see fit. */
    options += "Numeric max_cpu_time          0.5\n";    // 单位:s

    /* Place to return solution. */
    CppAD::ipopt::solve_result<Dvector> solution;

    /* Solve the problem. */
    // cout << "Solve the problem......" << endl;
    CppAD::ipopt::solve<Dvector, FG_eval>(options, vars, vars_lower_bounds, vars_upper_bounds, constraints_lower_bounds, constraints_upper_bounds, fg_eval, solution);

    /* Check some of the solution values. */
    ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;

    /* Cost! */
    // auto cost = solution.obj_value;
    // std::cout << "Cost: " << cost << std::endl;

    /* Return the first actuator values. The variables can be accessed with 'solution.x'. */
    std::vector<double> result;
    result.clear();
    // cout << solution.x << endl;
    // cout << front_wheel_angle_start << endl;

    result.push_back(solution.x);
    result.push_back(solution.x);

    /* Add 'future' solutions (where MPC is going). */
    for (size_t i = 0; i < Np - 1; i++) {
      result.push_back(solution.x);
      result.push_back(solution.x);
    }
    // std::cout << "end now" << std::endl;
    return result;
}
代价的权重:
# MPC 目标函数里面可以调节的权重
    mpc_cte_weight_int:600 # ok
    mpc_epsi_weight_int: 1000 # ok
    mpc_v_weight_int: 200 # ok real 100
    # 控制量幅值代价权重
    mpc_steer_actuator_cost_weight_int: 400 # ok
    mpc_acc_actuator_cost_weight_int: 100 # ok
    # 前后两次控制量变化的代价权重
    mpc_change_steer_cost_weight_int: 200 # ok
    mpc_change_accel_cost_weight_int: 200 # ok
四、效果展示

实验过程中发如今相同的权重下,给定不同的求解时间,会对MPC的性能产生较大的影响:
options += "Numeric max_cpu_time          0.5\n";    // 单位:s
求解时间为0.5s的效果,计时发现求解一次的时间在50ms左右,但是偶然会到200-300ms,跟踪效果良好,无振荡。
https://i-blog.csdnimg.cn/direct/9997df2cf9e34853bd29a45f56707645.png
求解时间为0.2s的效果,求解时间在50ms左右,最大求解时间被限制在200ms左右。
https://i-blog.csdnimg.cn/direct/ecd2a8b579094b5eb8283a9f38f21778.png
跟踪直线轨迹时出现了轻微振荡。
https://i-blog.csdnimg.cn/direct/531b7e5f3d1548c39d0212c581dd63cf.png
求解时间为0.05s的效果,最大求解时间被限制在50ms-70ms之间。
https://i-blog.csdnimg.cn/direct/c939725dbbda4ad29e92c56c2e3edecc.png
跟踪直线轨迹时出现显着振荡:
https://i-blog.csdnimg.cn/direct/7b516b960cbf4fa7aaab31e78089353f.png
实际工程实现中,需要权衡求解精度与实时性,应当通过实验和工程束缚确定最大求解时间等参数。

   主动驾驶控制与规划——Project 4: MPC车辆控制


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 主动驾驶控制与规划——Project 4: MPC车辆控制