Apollo_PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZE 非线性速度优化

目录

PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER

利用二次优化进行速度点集平滑

查看speedlimit是否可行

对道路曲率进行平滑

对speedLimit进行平滑

利用IPOPT进行速度非线性优化

构造非线性优化器实例

设置s的上下界范围

设置path_curvature 和speed_limit

设置warm_start

设置s_reference

设置权重

构造IPOPT优化问题

ptr_interface构造优化问题

Overview

get_nlp_info

get_bounds_info

get_starting_point

eval_f

eval_grad_f

eval_g

eval_jac_g

eval_h

get_optimization_results & finalize_solution


PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER

piecewise_jerk_speed_optimizer速度优化器构造凸优化问题得到进行速度规划. 这里介绍非线性速度优化器piecewise_jerk_nonlinear_speed_optimizer.

先讲下为什么需要使用非线性速度规划, 如下图,基于二次规划的速度规划中,pi是曲率关于时间t的函数,但实际上路径的曲率是与s相关的。二次规划在原先动态规划出来的粗糙ST曲线上将关于s的曲率惩罚转化为关于t的曲率惩罚,如此,当二次规划曲线与动态规划曲线差别不大,规划出来基本一致;若规划差别大,则会差别很大。就如图所示,规划出来的区间差别较大。限速/曲率的函数是关于s的函数,而s是我们要求的优化量,只能通过动态规划进行转化,如此就会使得二次规划的速度约束不精确。为了使得限速更加精细,Apollo提出了一种基于非线性规划的速度规划方法, 限速/曲率函数是关于s的非线性函数。

这个task的主要功能是对上一步搜索出的速度轨迹进行平滑,从而得到一条平滑、舒适的速度轨迹,里面涉及到二次优化平滑及非线性优化。主要包含以下及部分:

利用二次优化进行速度点集平滑
 
 

//利用二次优化进行速度点集平滑,首先得到一个初始平滑的速度点集 //这里相当于做了一次PIECEWISE_JERK_SPEED_OPTIMIZER const auto qp_start = std::chrono::system_clock::now(); const auto qp_smooth_status = OptimizeByQP(speed_data, &distance, &velocity, &acceleration); const auto qp_end = std::chrono::system_clock::now(); std::chrono::duration<double> qp_diff = qp_end - qp_start; ADEBUG << "speed qp optimization takes " << qp_diff.count() * 1000.0 << " ms";

先利用二次优化的方法对速度点集进行初次平滑。一些优化问题中的参数设定如下:

delta_t:0.1 ;total_length:等于path的总长度; total_time:7.0

优化问题的代价函数构造方式如下:

优化变量为ST坐标系下的s值,s一阶导及s二阶导, s三阶导。可以看到,与路径规划的优化问题构造形式还是比较类似的,除了这里用到了s_ref作为s值的标准,s_ref是根据上一步生成的离散点集,用更小的单位(delta_t=0.1s)来进行线性差值。这样也就引入了一次项,因此利用osqp优化库来求解的时候,要将q向量进行赋值。

对于优化问题中的限制约束,这里和path的规划限制完全是一样的,在Apollo的代码中可以看到,两个task都用了优化问题基类下的CalculateAffineConstraint函数,因此两者的限制约束是完全一样的,只是对于变量的上下限值,变量的初始值有所出入。

 

void PiecewiseJerkProblem::CalculateAffineConstraint( std::vector<c_float>* A_data, std::vector<c_int>* A_indices, std::vector<c_int>* A_indptr, std::vector<c_float>* lower_bounds, std::vector<c_float>* upper_bounds)

查看speedlimit是否可行

如果当前时刻的速度已经超越了在这个位置的道路限速,则会返回错误。只有在满足该条件下才能进行后面的非线性优化,否则直接输出上一步的二次优化结果。

 

bool PiecewiseJerkSpeedNonlinearOptimizer::CheckSpeedLimitFeasibility() { // a naive check on first point of speed limit static constexpr double kEpsilon = 1e-6; const double init_speed_limit = speed_limit_.GetSpeedLimitByS(s_init_); if (init_speed_limit + kEpsilon < s_dot_init_) { AERROR << "speed limit [" << init_speed_limit << "] lower than initial speed[" << s_dot_init_ << "]"; return false; } return true; }

对道路曲率进行平滑

对生成的path点的曲率值进行平滑,代价函数如下所示, 其中x_i表示道路点的曲率值,这一步曲率的平滑是为后面的速度非线性优化做铺垫。得到光滑的kappa-s curve, 优化变量是每个s处的kappa,kappa_d, kappa_dd,参考kappa_ref由path_data计算得出

使用了PiecewiseJerkPathProblem类(PIECEWISE_JERK_PATH_OPTIMIZER的主要类),

 

//对道路曲率进行平滑 Status PiecewiseJerkSpeedNonlinearOptimizer::SmoothPathCurvature( const PathData& path_data) { // using piecewise_jerk_path to fit a curve of path kappa profile // TODO(Jinyun): move smooth configs to gflags // 得到光滑的kappa-s curve, 优化变量是每个s处的kappa,kappa_d, kappa_dd // 参考kappa_ref由path_data计算得出 const auto& cartesian_path = path_data.discretized_path(); const double delta_s = 0.5; std::vector<double> path_curvature; for (double path_s = cartesian_path.front().s(); path_s < cartesian_path.back().s() + delta_s; path_s += delta_s) { const auto& path_point = cartesian_path.Evaluate(path_s); path_curvature.push_back(path_point.kappa()); } const auto& path_init_point = cartesian_path.front(); std::array<double, 3> init_state = {path_init_point.kappa(), path_init_point.dkappa(), path_init_point.ddkappa()}; PiecewiseJerkPathProblem piecewise_jerk_problem(path_curvature.size(), delta_s, init_state); piecewise_jerk_problem.set_x_bounds(-1.0, 1.0); piecewise_jerk_problem.set_dx_bounds(-10.0, 10.0); piecewise_jerk_problem.set_ddx_bounds(-10.0, 10.0); piecewise_jerk_problem.set_dddx_bound(-10.0, 10.0); piecewise_jerk_problem.set_weight_x(0.0); piecewise_jerk_problem.set_weight_dx(10.0); piecewise_jerk_problem.set_weight_ddx(10.0); piecewise_jerk_problem.set_weight_dddx(10.0); //TODOLIU:这里为什么要把path_curvature当成x_ref塞进去 piecewise_jerk_problem.set_x_ref(10.0, std::move(path_curvature)); if (!piecewise_jerk_problem.Optimize(1000)) { const std::string msg = "Smoothing path curvature failed"; AERROR << msg; return Status(ErrorCode::PLANNING_ERROR, msg); } std::vector<double> opt_x; std::vector<double> opt_dx; std::vector<double> opt_ddx; opt_x = piecewise_jerk_problem.opt_x(); opt_dx = piecewise_jerk_problem.opt_dx(); opt_ddx = piecewise_jerk_problem.opt_ddx(); PiecewiseJerkTrajectory1d smoothed_path_curvature( opt_x.front(), opt_dx.front(), opt_ddx.front()); for (size_t i = 1; i < opt_ddx.size(); ++i) { double j = (opt_ddx[i] - opt_ddx[i - 1]) / delta_s; smoothed_path_curvature.AppendSegment(j, delta_s); } smoothed_path_curvature_ = smoothed_path_curvature; return Status::OK(); }

对speedLimit进行平滑

对道路限速speedLimit进行平滑优化,相同的代价函数及限制约束条件。概括来讲,这一步和对道路曲率进行平滑的目的相同,都是尽可能将后面非线性速度优化的输入构造的尽可能平滑,从而生成较好的速度优化效果。

我们具体讨论一下为什么需要先进行限速平滑。限速的函数并非直接可以得到,它来自于告警地图限速,交通规则限速, 向心加速度限速,绕行障碍物限速,将所有的限速函数相加,得到下图的限速函数,很明显,该函数既不连续也不可导,所以需要对其进行平滑处理。

对于限速曲线的平滑,Apollo采样分段多项式进行平滑,之后采样二次规划的方式进行求解。限速曲线的目标函数如下, 如此,我们就有了连续且可导的限速曲线。

 

//对speedLimit进行平滑 Status PiecewiseJerkSpeedNonlinearOptimizer::SmoothSpeedLimit() { // using piecewise_jerk_path to fit a curve of speed_ref // TODO(Hongyi): move smooth configs to gflags double delta_s = 2.0; std::vector<double> speed_ref; for (int i = 0; i < 100; ++i) { double path_s = i * delta_s; double limit = speed_limit_.GetSpeedLimitByS(path_s); speed_ref.emplace_back(limit); } std::array<double, 3> init_state = {speed_ref[0], 0.0, 0.0}; PiecewiseJerkPathProblem piecewise_jerk_problem(speed_ref.size(), delta_s, init_state); piecewise_jerk_problem.set_x_bounds(0.0, 50.0); piecewise_jerk_problem.set_dx_bounds(-10.0, 10.0); piecewise_jerk_problem.set_ddx_bounds(-10.0, 10.0); piecewise_jerk_problem.set_dddx_bound(-10.0, 10.0); piecewise_jerk_problem.set_weight_x(0.0); piecewise_jerk_problem.set_weight_dx(10.0); piecewise_jerk_problem.set_weight_ddx(10.0); piecewise_jerk_problem.set_weight_dddx(10.0); piecewise_jerk_problem.set_x_ref(10.0, std::move(speed_ref)); if (!piecewise_jerk_problem.Optimize(4000)) { const std::string msg = "Smoothing speed limit failed"; AERROR << msg; return Status(ErrorCode::PLANNING_ERROR, msg); } std::vector<double> opt_x; std::vector<double> opt_dx; std::vector<double> opt_ddx; opt_x = piecewise_jerk_problem.opt_x(); opt_dx = piecewise_jerk_problem.opt_dx(); opt_ddx = piecewise_jerk_problem.opt_ddx(); PiecewiseJerkTrajectory1d smoothed_speed_limit(opt_x.front(), opt_dx.front(), opt_ddx.front()); for (size_t i = 1; i < opt_ddx.size(); ++i) { double j = (opt_ddx[i] - opt_ddx[i - 1]) / delta_s; smoothed_speed_limit.AppendSegment(j, delta_s); } smoothed_speed_limit_ = smoothed_speed_limit; return Status::OK(); }

利用IPOPT进行速度非线性优化

由函数PiecewiseJerkSpeedNonlinearOptimizer::OptimizeByNLP实现。

 

Status PiecewiseJerkSpeedNonlinearOptimizer::OptimizeByNLP( std::vector<double>* distance, std::vector<double>* velocity, std::vector<double>* acceleration)

参数配置

 

default_task_config: { task_type: PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER piecewise_jerk_nonlinear_speed_optimizer_config { acc_weight: 2.0 jerk_weight: 3.0 lat_acc_weight: 1000.0 s_potential_weight: 0.05 ref_v_weight: 5.0 ref_s_weight: 100.0 soft_s_bound_weight: 1e6 use_warm_start: true } }

基于非线性规划的速度规划步骤与之前规划步骤基本一致, 采样方式为等间隔的时间采样。slower 与supper为松弛变量,防止求解失败。

构造非线性优化器实例

这里new了一个PiecewiseJerkSpeedNonlinearIpoptInterface类的对象实例,这个类继承了IPOPT库,通过这个接口类,可以将规划问题的代价函数、限制条件等转成IPOPT库求解时所需要的形式。这一步通过代码可以看出将规划问题的初始参数全部传入进去,包括规划初始点信息、优化问题的维度、单位、优化变量的上下限值等等。

 

// Set optimizer instance auto ptr_interface = new PiecewiseJerkSpeedNonlinearIpoptInterface( s_init_, s_dot_init_, s_ddot_init_, delta_t_, num_of_knots_, total_length_, s_dot_max_, s_ddot_min_, s_ddot_max_, s_dddot_min_, s_dddot_max_);

设置s的上下界范围

将st_graph_data处理过后的s_boundary赋值进接口类的对象中,

 

ptr_interface->set_safety_bounds(s_bounds_);

设置path_curvature 和speed_limit

传入平滑后的path_curvature曲线和speed_limit曲线,

 

ptr_interface->set_curvature_curve(smoothed_path_curvature_); ptr_interface->set_speed_limit_curve(smoothed_speed_limit_);

设置warm_start

这一步warm_start设置的就是之前QP优化后的变量结果,因此NLP是基于QP后的结果再进行的一次优化

 

// TODO(Jinyun): refactor warms start setting API if (config.use_warm_start()) { const auto& warm_start_distance = *distance; const auto& warm_start_velocity = *velocity; const auto& warm_start_acceleration = *acceleration; if (warm_start_distance.empty() || warm_start_velocity.empty() || warm_start_acceleration.empty() || warm_start_distance.size() != warm_start_velocity.size() || warm_start_velocity.size() != warm_start_acceleration.size()) { const std::string msg = "Piecewise jerk speed nonlinear optimizer warm start invalid!"; AERROR << msg; return Status(ErrorCode::PLANNING_ERROR, msg); } std::vector<std::vector<double>> warm_start; std::size_t size = warm_start_distance.size(); for (std::size_t i = 0; i < size; ++i) { warm_start.emplace_back(std::initializer_list<double>( {warm_start_distance[i], warm_start_velocity[i], warm_start_acceleration[i]})); } ptr_interface->set_warm_start(warm_start); }

设置s_reference

这一步设置优化变量s的参考值,可以使用QP优化出来的distance向量., 也可以使用默认值

 

if (FLAGS_use_smoothed_dp_guide_line) { ptr_interface->set_reference_spatial_distance(*distance); // TODO(Jinyun): move to confs ptr_interface->set_w_reference_spatial_distance(10.0); } else { std::vector<double> spatial_potantial(num_of_knots_, total_length_); ptr_interface->set_reference_spatial_distance(spatial_potantial); ptr_interface->set_w_reference_spatial_distance( config.s_potential_weight()); }

设置权重

设置优化变量的权重值,包括加速度、加加速度、向心加速度权重。设置参考速度及参考速度权重,这边的参考速度直接设为了cruise_speed。

 

ptr_interface->set_w_overall_a(config.acc_weight()); ptr_interface->set_w_overall_j(config.jerk_weight()); ptr_interface->set_w_overall_centripetal_acc(config.lat_acc_weight()); ptr_interface->set_reference_speed(cruise_speed_); ptr_interface->set_w_reference_speed(config.ref_v_weight());

构造IPOPT优化问题

构造接口类的智能指针来存放优化问题的具体形式 ,并调用IPOPT进行求解. 将构造好的接口类指针ptr_interface传入problem中,再调用OptimizeTNLP对优化问题进行求解。

 

Ipopt::SmartPtr<Ipopt::TNLP> problem = ptr_interface; Ipopt::SmartPtr<Ipopt::IpoptApplication> app = IpoptApplicationFactory(); app->Options()->SetIntegerValue("print_level", 0); app->Options()->SetIntegerValue("max_iter", 1000); Ipopt::ApplicationReturnStatus status = app->Initialize(); if (status != Ipopt::Solve_Succeeded) { const std::string msg = "Piecewise jerk speed nonlinear optimizer failed during initialization"; AERROR << msg; return Status(ErrorCode::PLANNING_ERROR, msg); } const auto start_timestamp = std::chrono::system_clock::now(); status = app->OptimizeTNLP(problem);

ptr_interface构造优化问题
Overview

对于此问题, 我们根据代码将问题用公式写出, 并使用ipopt的调用方式进行展示。

求解问题:

PiecewiseJerkSpeedNonlinearIpoptInterface() 原理解析. 介绍ptr_interface中对于优化问题是如何构造的, 将优化问题的数学表达式写出来,看对于非线性速度优化,Apollo是如何设计优化问题的。

  • 代价函数:

  • 代价函数与QpSpeedOptimizer中的代价函数很类似,只是多了关于向心加速度的最后一项,因此这一步其实是在考虑向心加速度的基础上对QP的结果又一次平滑

f(s→)=wref−s⋅∑i=0n−1(si−s−refi)2+wref−v⋅∑i=0n−1(s˙i−v−ref)2+wa⋅∑i=0n−1s¨i2+wj⋅∑i=0n−2(s¨i+1−s¨ideltat)2+wc−a⋅∑i=0n−1(s˙i⋅s˙i∙ kappa i)2+wtar_s(xnp−1−xtar)2+wtar_v(x˙2∗np−2−vtar)2+wtar_a(x¨3∗np−3−atar)2+wsoft_s_low∑i=0n−1slow_slack+wsoft_s_upper∑i=0n−1supper_slack

  • 约束条件:

  • 约束条件也与QP中的约束十分相似,唯一不同之处在于对于speed_limit的非线性约束。到这,我们可以知道为什么在进行非线性优化这步之前,需要对path的曲率以及speed_limit曲线进行平滑了,因为在这里都得用上它们平滑后的结果,曲率和限速越平滑,优化出的速度曲线也就越平滑。其起始点约束是通过待优化变量的上下限实现的。

  • vmax∗dt>=si+1−si>=0.0, np−1 s monotone constraints

  • |s¨i+1−s¨i|/dt<=s⃛max, np−1 jerk bound constraint

  • si+1−si−s˙i∗dt−13∗s¨i∗dt2−16∗s¨i+1∗dt2=0, np−1 position equality constraints

  • s˙i+1−s˙i−12∗dt∗s¨i−12∗dt∗s¨i+1=0, np−1 velocity equality constraints

  • s˙i−v_bound_func_(si)<=0.0,,np−1speed limit constraints

  • si−sisoft_low_slack+silow_slack>=0.0, np−1 soft safety low boundary constraints

  • si−sisoft_upper_slack+siupper_slack>=0.0, np−1 soft safety upper boundary constraints

定义点的数目num_of_points为np.

get_nlp_info
 

bool PiecewiseJerkSpeedNonlinearIpoptInterface::get_nlp_info( int &n, int &m, int &nnz_jac_g, int &nnz_h_lag, IndexStyleEnum &index_style)

  • 待优化变量n=5∗np

  • x=[s0,s1,...vnp−1,|v0,s1,...vnp−1,|a0,a1,...anp−1,|s0low_slack,s1low_slack,...snp−1low_slack,|s0low_slack,s1low_slack,...snp−1low_slack]T

  • n=5∗np ,即每个时间dt处的 s,s˙,s¨,slow_slack,supper_slack .

  • 约束数量 m=7(np−1)

  • s的单调性约束 np−1个

  • vmax∗dt>=si+1−si>=0.0, np−1 s monotone constraints

  • jerk的上下界约束 np−1个

  • |s¨i+1−s¨i|/dt<=s⃛max, np−1 jerk bound constraint

  • 位置相等约束,即位置连续约束 np−1个

  • si+1−si−s˙i∗dt−13∗s¨i∗dt2−16∗s¨i+1∗dt2=0, np−1 position equality constraints

  • 速度相等约束, np−1个

  • s˙i+1−s˙i−12∗dt∗s¨i−12∗dt∗s¨i+1=0, np−1 velocity equality constraints

  • speed_limit约束,np−1个

  • s˙i−v_bound_func_(si)<=0.0,,np−1speed limit constraints

  • s上下界松弛约束,2(np−1)个

  • si−sisoft_low_slack+silow_slack>=0.0, np−1 soft safety low boundary constraints

  • si−sisoft_upper_slack+siupper_slack>=0.0, np−1 soft safety upper boundary constraints

  • 雅可比矩阵非0项数量 nnz_jac_g=19(np−1)

  • s的单调性约束产生的非零元素 2(np−1)个

  • jerk的上下界约束产生的非零元素 2(np−1)个

  • 位置相等约束,即位置连续约束产生的非零元素 5(np−1)个

  • 速度相等约束产生的非零元素 4(np−1)个

  • speed_limit约束产生的非零元素 2(np−1)个

  • s上下界松弛约束产生的非零元素 4(np−1)个

  • 黑塞矩阵非0项数量nnz_h_lag=5np−1

  • 因为目标函数里面有5*n_p个待优化变量, 且每一项为为二次函数,求解二阶导后不为0.

get_bounds_info
 

bool PiecewiseJerkSpeedNonlinearIpoptInterface::get_bounds_info( int n, double *x_l, double *x_u, int m, double *g_l, double *g_u)

  • 待优化变量的上下界

  • x_l<=x<=x_u

  • 待优化变量s,s˙,s¨的上下边界

// bounds for variables

// s

x_l[0] = s_init_;

x_u[0] = s_init_;

for (int i = 1; i < num_of_points_; ++i) {

x_l[i] = safety_bounds_[i].first;

x_u[i] = safety_bounds_[i].second;

}

 
 

// s_dot

x_l[v_offset_] = s_dot_init_;

x_u[v_offset_] = s_dot_init_;

for (int i = 1; i < num_of_points_; ++i) {

x_l[v_offset_ + i] = 0.0;

x_u[voffset_ + i] = LARGE_VELOCITY_VALUE;

}

// s_ddot

x_l[a_offset_] = s_ddot_init_;

x_u[a_offset_] = s_ddot_init_;

for (int i = 1; i < num_of_points_; ++i) {

x_l[a_offset_ + i] = s_ddot_min_;

x_u[a_offset_ + i] = s_ddot_max_;

}

  • 待优化变量slow_slack,supper_slack的上下边界

 

for (int i = 0; i < num_of_points_; ++i) {

x_l[lower_s_slack_offset_ + i] = 0.0;

x_u[lower_s_slack_offset_ + i] = INF;

}

 
 

// upper_s_slack

for (int i = 0; i < num_of_points_; ++i) {

x_l[upper_s_slack_offset_ + i] = 0.0;

x_u[upper_s_slack_offset_ + i] = INF;

  • 约束函数的上下界

  • g_l<=g(x)<=g_u

  • s的单调性约束 np−1个

  • vmax∗dt>=si+1−si>=0.0, np−1 s monotone constraints

 

for (int i = 0; i + 1 < num_of_points_; ++i) {

g_l[i] = 0.0;

g_u[i] = LARGE_VELOCITY_VALUE * delta_t_;

}

  • jerk的上下界约束 np−1个

  • |s¨i+1−s¨i|/dt<=s⃛max, np−1 jerk bound constraint

 

int offset = num_of_points_ - 1;

for (int i = 0; i + 1 < num_of_points_; ++i) {

g_l[offset + i] = s_dddot_min_;

g_u[offset + i] = s_dddot_max_;

}

  • 位置相等约束,即位置连续约束 np−1个

  • si+1−si−s˙i∗dt−13∗s¨i∗dt2−16∗s¨i+1∗dt2=0, np−1 position equality constraints

 

offset += num_of_points_ - 1;

for (int i = 0; i + 1 < num_of_points_; ++i) {

g_l[offset + i] = 0.0;

g_u[offset + i] = 0.0;

}

  • 速度相等约束, np−1个

  • s˙i+1−s˙i−12∗dt∗s¨i−12∗dt∗s¨i+1=0, np−1 velocity equality constraints

 

offset += num_of_points_ - 1;

for (int i = 0; i + 1 < num_of_points_; ++i) {

g_l[offset + i] = 0.0;

g_u[offset + i] = 0.0;

 
 

}

  • speed_limit约束,np−1个

  • s˙i−v_bound_func_(si)<=0.0,,np−1speed limit constraints

 

offset += num_of_points_ - 1;

 
 

for (int i = 0; i < num_of_points_; ++i) {

 
 

g_l[offset + i] = -INF;

 
 

g_u[offset + i] = 0.0;

 
 

}

  • s上下界松弛约束,2(np−1)个

  • si−sisoft_low_slack+silow_slack>=0.0, np−1 soft safety low boundary constraints

  • si−sisoft_upper_slack+siupper_slack>=0.0, np−1 soft safety upper boundary constraints

 

offset += num_of_points_;

 
 

for (int i = 0; i < num_of_points_; ++i) {

 
 

g_l[offset + i] = 0.0;

 
 

g_u[offset + i] = INF;

 
 

}

 
 

// s_i - soft_upper_s_i - upper_slack_i <= 0.0

 
 

offset += num_of_points_;

 
 

for (int i = 0; i < num_of_points_; ++i) {

 
 

g_l[offset + i] = -INF;

 
 

g_u[offset + i] = 0.0;

 
 

}

get_starting_point
 

bool PiecewiseJerkSpeedNonlinearIpoptInterface::get_starting_point( int n, bool init_x, double *x, bool init_z, double *z_L, double *z_U, int m, bool init_lambda, double *lambda)

方式1:

目前使用的初始值,如果x_warm_start_.empty() == false, xp,xv,xa使用warm start得到的值; xlowslack,xupperslack设置成0.

如果怎么办?如果x_warm_start_.empty()==true怎么办?

这个warm start的值是通过求解qp速度规划问题(task PIECEWISE_JERK_SPEED_OPTIMIZER),得到符合约束的速度平滑曲线,作为非线性规划的初值.

方式2:

 

for (int i = 0; i < num_of_points_; ++i) { x[i] = std::min(5.0 * delta_t_ * i + s_init_, s_max_); } x[0] = s_init_; for (int i = 0; i < num_of_points_; ++i) { x[v_offset_ + i] = 5.0; } x[v_offset_] = s_dot_init_; for (int i = 0; i < num_of_points_; ++i) { x[a_offset_ + i] = 0.0; } x[a_offset_] = s_ddot_init_; if (use_soft_safety_bound_) { for (int i = 0; i < num_of_points_; ++i) { x[lower_s_slack_offset_ + i] = 0.0; x[upper_s_slack_offset_ + i] = 0.0; } }

eval_f
 

bool PiecewiseJerkSpeedNonlinearIpoptInterface::eval_f(int n, const double *x, bool new_x, double &obj_value)

目标函数

f(s→)=wref−s⋅∑i=0n−1(si−s−refi)2+wref−v⋅∑i=0n−1(s˙i−v−ref)2+wa⋅∑i=0n−1s¨i2+wj⋅∑i=0n−2(s¨i+1−s¨ideltat)2+wc−a⋅∑i=0n−1(s˙i⋅s˙i∙ kappa i)2+wtar_s(xnp−1−xtar)2+wtar_v(x˙2∗np−2−vtar)2+wtar_a(x¨3∗np−3−atar)2+wsoft_s_low∑i=0n−1slow_slack+wsoft_s_upper∑i=0n−1supper_slack

  • 第一项尽量贴近sref

 

// difference between ref spatial distace

 
 

for (int i = 0; i < num_of_points_; ++i) {

 
 

double s_diff = x[i] - s_ref_[i];

 
 

obj_value += s_diff * s_diff * w_ref_s_;

 
 

}

  • 第二项尽量贴近v_ref

 

// difference between ref speed

 
 

for (int i = 0; i < num_of_points_; ++i) {

 
 

double v_diff = x[v_offset_ + i] - v_ref_;

 
 

obj_value += v_diff * v_diff * w_ref_v_;

 
 

}

  • 第三项加速度的errfort尽可能小

 

// acceleration obj.

 
 

for (int i = 0; i < num_of_points_; ++i) {

 
 

double a = x[a_offset_ + i];

 
 

obj_value += a * a * w_overall_a_;

 
 

}

  • 第四项jerk的effort尽可能小

 

// jerk obj.

 
 

for (int i = 0; i + 1 < num_of_points_; ++i) {

 
 

double j = (x[a_offset_ + i + 1] - x[a_offset_ + i]) / delta_t_;

 
 

obj_value += j * j * w_overall_j_;

 
 

}

  • 第五项横向加速度的effort尽可能小

 

// centripetal acceleration obj.

 
 

for (int i = 0; i < num_of_points_; ++i) {

 
 

double v = x[v_offset_ + i];

 
 

double s = x[i];

 
 

double kappa = curvature_curve_.Evaluate(0, s);

 
 

double a_lat = v * v * kappa;

 
 

obj_value += a_lat * a_lat * w_overall_centripetal_acc_;

 
 

}

  • 第六项s, v, a终端约束(此处has_end_state_target_ == false,未使用该约束)

  • wtar_s(xnp−1−xtar)2+wtar_v(x˙2∗np−2−vtar)2+wtar_a(x¨3∗np−3−atar)2

 

double s_diff = x[num_of_points_ - 1] - s_target_;

 
 

obj_value += s_diff * s_diff * w_target_s_;

 
 
 
 

double v_diff = x[v_offset_ + num_of_points_ - 1] - v_target_;

 
 

obj_value += v_diff * v_diff * w_target_v_;

 
 
 
 

double a_diff = x[a_offset_ + num_of_points_ - 1] - a_target_;

 
 

obj_value += a_diff * a_diff * w_target_a_;

  • 第七项使用软安全约束 (有无使用有无使用?)

  • wsoft_s_low∑i=0n−1slow_slack+wsoft_s_upper∑i=0n−1supper_slack

 

for (int i = 0; i < num_of_points_; ++i) {

 
 

obj_value += x[lower_s_slack_offset_ + i] * w_soft_s_bound_;

 
 

obj_value += x[upper_s_slack_offset_ + i] * w_soft_s_bound_;

 
 

}

eval_grad_f

目标函数

+[wtar_s(xnp−1−xtar)2+wtar_v(x˙2∗np−2−vtar)2+wtar_a(x¨3∗np−3−atar)2]

+[wsoft_s_low∑i=0n−1slow_slack+wsoft_s_upper∑i=0n−1supper_slack]

待优化变量

x=[s0,s1,...vnp−1,|v0,s1,...vnp−1,|a0,a1,...anp−1,|s0low_slack,s1low_slack,...snp−1low_slack,|s0low_slack,s1low_slack,...snp−1low_slack]T

对f(s)针对各个变量 s,s˙,s¨,slow_slack,supper_slack 求导. f(s)是一个5np∗1的行向量.

Δf=[∂fs[0],∂fs[1],…,∂fs[np−1],|∂fv[0],∂fv[1],…,∂fv[np−1],|∂fa[0],∂fa[1],…,∂fa[np−1]|∂fslow_slack[0],∂fslow_slack[1],…,∂fslow_slack[np−1],|∂fsupper_slack[0],∂fsupper_slack[1],…,∂fsupper_slack[np−1]]T

 

// ref. spatial distance objective for (int i = 0; i < num_of_points_; ++i) { auto s_diff = x[i] - s_ref_[i]; grad_f[i] += 2.0 * s_diff * w_ref_s_; } // ref. speed objective for (int i = 0; i < num_of_points_; ++i) { auto v_diff = x[v_offset_ + i] - v_ref_; grad_f[v_offset_ + i] += 2.0 * v_diff * w_ref_v_; } // jerk objective double c = 2.0 / (delta_t_ * delta_t_) * w_overall_j_; grad_f[a_offset_] += -c * (x[a_offset_ + 1] - x[a_offset_]); for (int i = 1; i + 1 < num_of_points_; ++i) { grad_f[a_offset_ + i] += c * (2.0 * x[a_offset_ + i] - x[a_offset_ + i + 1] - x[a_offset_ + i - 1]); } grad_f[a_offset_ + num_of_points_ - 1] += c * (x[a_offset_ + num_of_points_ - 1] - x[a_offset_ + num_of_points_ - 2]); // acceleration objective for (int i = 0; i < num_of_points_; ++i) { grad_f[a_offset_ + i] += 2.0 * x[a_offset_ + i] * w_overall_a_; } // centripetal acceleration objective for (int i = 0; i < num_of_points_; ++i) { double v = x[v_offset_ + i]; double v2 = v * v; double v3 = v2 * v; double v4 = v3 * v; double s = x[i]; double kappa = curvature_curve_.Evaluate(0, s); double kappa_dot = curvature_curve_.Evaluate(1, s); grad_f[i] += 2.0 * w_overall_centripetal_acc_ * v4 * kappa * kappa_dot; grad_f[v_offset_ + i] += 4.0 * w_overall_centripetal_acc_ * v3 * kappa * kappa; } if (has_end_state_target_) { double s_diff = x[num_of_points_ - 1] - s_target_; grad_f[num_of_points_ - 1] += 2.0 * s_diff * w_target_s_; double v_diff = x[v_offset_ + num_of_points_ - 1] - v_target_; grad_f[v_offset_ + num_of_points_ - 1] += 2.0 * v_diff * w_target_v_; double a_diff = x[a_offset_ + num_of_points_ - 1] - a_target_; grad_f[a_offset_ + num_of_points_ - 1] += 2.0 * a_diff * w_target_a_; } if (use_soft_safety_bound_) { for (int i = 0; i < num_of_points_; ++i) { grad_f[lower_s_slack_offset_ + i] += w_soft_s_bound_; grad_f[upper_s_slack_offset_ + i] += w_soft_s_bound_; } }

eval_g
 

bool PiecewiseJerkSpeedNonlinearIpoptInterface::eval_g(int n, const double *x, bool new_x, int m, double *g)

s的单调性约束 np−1个

vmax∗dt>=si+1−si>=0.0, np−1 s monotone constraints

g[i]=si+1−si,i∈[0,np−1]

 

// s monotone constraints s_i+1 - s_i for (int i = 0; i + 1 < num_of_points_; ++i) { g[i] = x[offset + i + 1] - x[i]; }

jerk的上下界约束 np−1个

|s¨i+1−s¨i|/dt<=s⃛max, np−1 jerk bound constraint

g[i]=(s¨i+1−s¨i)/dt,i∈[np,2np−1]

位置相等约束,即位置连续约束 np−1个

si+1−si−s˙i∗dt−13∗s¨i∗dt2−16∗s¨i+1∗dt2=0, np−1 position equality constraints

g[i]=si+1−si−s˙i∗dt−13∗s¨i∗dt2−16∗s¨i+1∗dt2,i∈[2np,3np−1]

速度相等约束, np−1个

s˙i+1−s˙i−12∗dt∗s¨i−12∗dt∗s¨i+1=0, np−1 velocity equality constraints

g[i]=s˙i+1−s˙i−12∗dt∗s¨i−12∗dt∗s¨i+1,i∈[3np,4np−1]

 

//位置相等约束,即位置连续约束 $n_p -1$个 //速度相等约束, $n_p -1$个 //speed_limit约束,$n_p -1$个 int coffset_jerk = offset; int coffset_position = coffset_jerk + num_of_points_ - 1; int coffset_velocity = coffset_position + num_of_points_ - 1; double t = delta_t_; double t2 = t * t; double t3 = t2 * t; for (int i = 0; i + 1 < num_of_points_; ++i) { double s0 = x[i]; double s1 = x[i + 1]; double v0 = x[v_offset_ + i]; double v1 = x[v_offset_ + i + 1]; double a0 = x[a_offset_ + i]; double a1 = x[a_offset_ + i + 1]; double j = (a1 - a0) / t; g[coffset_jerk + i] = j; g[coffset_position + i] = s1 - (s0 + v0 * t + 0.5 * a0 * t2 + 1.0 / 6.0 * j * t3); g[coffset_velocity + i] = v1 - (v0 + a0 * t + 0.5 * j * t2); }

speed_limit约束,np−1个

s˙i−v_bound_func_(si)<=0.0,,np−1speed limit constraints

g[i]=s˙i−v_bound_func_(si),i∈[4np,5np−1]

 

// speed limit constraints int coffset_speed_limit = offset; // s_dot_i - v_bound_func_(s_i) <= 0.0 for (int i = 0; i < num_of_points_; ++i) { double s = x[i]; double s_dot = x[v_offset_ + i]; g[coffset_speed_limit + i] = s_dot - v_bound_func_.Evaluate(0, s); }

s上下界松弛约束,2(np−1)个

si−sisoft_low_slack+silow_slack>=0.0, np−1 soft safety low boundary constraints

g[i]=si−sisoft_low_slack+silow_slack,i∈[5np,6np−1]

si−sisoft_upper_slack+siupper_slack>=0.0, np−1 soft safety upper boundary constraints

g[i]=si−sisoft_upper_slack+siupper_slack,i∈[6np,7np−1]

 

// soft safety boundary constraints int coffset_soft_lower_s = offset; // s_i - soft_lower_s_i + lower_slack_i >= 0.0 for (int i = 0; i < num_of_points_; ++i) { double s = x[i]; double lower_s_slack = x[lower_s_slack_offset_ + i]; g[coffset_soft_lower_s + i] = s - soft_safety_bounds_[i].first + lower_s_slack; } offset += num_of_points_; int coffset_soft_upper_s = offset; // s_i - soft_upper_s_i - upper_slack_i <= 0.0 for (int i = 0; i < num_of_points_; ++i) { double s = x[i]; double upper_s_slack = x[upper_s_slack_offset_ + i]; g[coffset_soft_upper_s + i] = s - soft_safety_bounds_[i].second - upper_s_slack; }

eval_jac_g

变量值:x 雅可比矩阵非0元素数量:nele_jac 雅可比矩阵值:values

 

bool PiecewiseJerkSpeedNonlinearIpoptInterface::eval_jac_g( int n, const double *x, bool new_x, int m, int nele_jac, int *iRow, int *jCol, double *values)

J=[∂g∂x1⋯∂g∂xn]=[∂g1∂x1⋯∂g1∂xn⋮⋱⋮∂gm∂x1⋯∂gm∂xnn]

J=[∂g1∂x,[∂g2∂x],...,[∂gm∂x]]

求解器通过稀疏矩阵(下面两个图是稀疏矩阵的一个例子)来保存值, 求解雅可比矩阵需要对约束函数进行求偏导.

s的单调性约束 np−1个 ∂g1∂x

vmax∗dt>=si+1−si>=0.0, np−1 s monotone constraints

g[i]=si+1−si,i∈[0,np−1] define g1

∂g1∂x 是 J的前np行, g1=[g1[0],g1[1],...g1[i],...,g1[np−1]]T以此为例, 写出雅克比矩阵,

∂g1∂x=[∂g1[0]x[0]=1∂g1[0]x[1]=−100000∂g1[1]x[0]=1∂g1[1]x[0]=−100000⋱000000∂g1[i]x[i]=1∂g1[i]x[i+1]=−100000⋱00000∂g1[np−2]x[np−2]=1∂g1[np−2]x[np−1]=−1]

 

//指定下标 // s monotone constraints s_i+1 - s_i for (int i = 0; i + 1 < num_of_points_; ++i) { // s_i iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = i; ++non_zero_index; // s_i+1 iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = i + 1; ++non_zero_index; ++constraint_index; } //给对应下标塞值 // s monotone constraints s_i+1 - s_i for (int i = 0; i + 1 < num_of_points_; ++i) { // s_i values[non_zero_index] = -1.0; ++non_zero_index; // s_i+1 values[non_zero_index] = 1.0; ++non_zero_index; }

jerk的上下界约束 np−1个g2

|s¨i+1−s¨i|/dt<=s⃛max, np−1 jerk bound constraint

g[i]=(s¨i+1−s¨i)/dt,i∈[np,2np−1]

∂g2∂x=[∂g2[0]x[0]=1dt∂g2[0]x[1]=−1dt00000∂g2[1]x[0]=1dt∂g2[1]x[0]=−1dt00000⋱000000∂g2[i]x[i]=1dt∂g2[i]x[i+1]=−1dt00000⋱00000∂g2[np−2]x[np−2]=1dt∂g2[np−2]x[np−1]=−1dt]

 

//指定下标 // jerk bound constraint, |s_ddot_i+1 - s_ddot_i| / delta_t <= s_dddot_max for (int i = 0; i + 1 < num_of_points_; ++i) { // a_i iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = a_offset_ + i; ++non_zero_index; // a_i+1 iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = a_offset_ + i + 1; ++non_zero_index; ++constraint_index; } //给对应下标塞值 // jerk bound constraint, |s_ddot_i+1 - s_ddot_i| / delta_t <= s_dddot_max for (int i = 0; i + 1 < num_of_points_; ++i) { // a_i values[non_zero_index] = -1.0 / delta_t_; ++non_zero_index; // a_i+1 values[non_zero_index] = 1.0 / delta_t_; ++non_zero_index; }

位置相等约束,即位置连续约束 np−1个

si+1−si−s˙i∗dt−13∗s¨i∗dt2−16∗s¨i+1∗dt2=0, np−1 position equality constraints

g[i]=si+1−si−s˙i∗dt−13∗s¨i∗dt2−16∗s¨i+1∗dt2,i∈[2np,3np−1]

对于∂g3∂x的第i行:

[0...∂g3[i]s[i]=−1∂g3[i]s[i+1]=1...0 | 0...∂g3[i]v[i]=−dt∂g3[i]v[i+1]=0...0| 0...∂g3[i]a[i]=−13dt2∂g3[i]a[i+1]=−16dt2...0|0...∂g3[i]slow_slack[i]=0∂g3[i]slow_slack[i+1]=0...0 | 0...∂g3[i]supper_slack[i]=0∂g3[i]supper_slack[1]=0...0 ]T

 

//指定下标 // position equality constraints for (int i = 0; i + 1 < num_of_points_; ++i) { // s_i iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = i; ++non_zero_index; // v_i iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = v_offset_ + i; ++non_zero_index; // a_i iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = a_offset_ + i; ++non_zero_index; // s_i+1 iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = i + 1; ++non_zero_index; // a_i+1 iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = a_offset_ + i + 1; ++non_zero_index; ++constraint_index; } //给对应下标塞值 // position equality constraints for (int i = 0; i + 1 < num_of_points_; ++i) { // s_i values[non_zero_index] = -1.0; ++non_zero_index; // v_i values[non_zero_index] = -delta_t_; ++non_zero_index; // a_i values[non_zero_index] = -1.0 / 3.0 * delta_t_ * delta_t_; ++non_zero_index; // s_i+1 values[non_zero_index] = 1.0; ++non_zero_index; // a_i+1 values[non_zero_index] = -1.0 / 6.0 * delta_t_ * delta_t_; ++non_zero_index; }

速度相等约束, np−1个

s˙i+1−s˙i−12∗dt∗s¨i−12∗dt∗s¨i+1=0, np−1 velocity equality constraints

g[i]=s˙i+1−s˙i−12∗dt∗s¨i−12∗dt∗s¨i+1,i∈[3np,4np−1]

对于∂g4∂x的第i行:

[0...∂g3[i]s[i]=0∂g3[i]s[i+1]=0...0 | 0...∂g3[i]v[i]=−1∂g3[i]v[i+1]=1...0| 0...∂g3[i]a[i]=12dt∂g3[i]a[i+1]=−12dt...0|0...∂g3[i]slow_slack[i]=0∂g3[i]slow_slack[i+1]=0...0 | 0...∂g3[i]supper_slack[i]=0∂g3[i]supper_slack[1]=0...0 ]T

 

//指定下标 // velocity equality constraints for (int i = 0; i + 1 < num_of_points_; ++i) { // v_i iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = v_offset_ + i; ++non_zero_index; // a_i iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = a_offset_ + i; ++non_zero_index; // v_i+1 iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = v_offset_ + i + 1; ++non_zero_index; // a_i+1 iRow[non_zero_index] = constraint_index; jCol[non_zero_index] = a_offset_ + i + 1; ++non_zero_index; ++constraint_index; } //给对应下标塞值 // velocity equality constraints for (int i = 0; i + 1 < num_of_points_; ++i) { // v_i values[non_zero_index] = -1.0; ++non_zero_index; // a_i values[non_zero_index] = -0.5 * delta_t_; ++non_zero_index; // v_i+1 values[non_zero_index] = 1.0; ++non_zero_index; // a_i+1 values[non_zero_index] = -0.5 * delta_t_; ++non_zero_index; }

speed_limit约束,np−1个

s˙i−v_bound_func_(si)<=0.0,,np−1speed limit constraints

g[i]=s˙i−v_bound_func_(si),i∈[4np,5np−1]

需要注意的是这里求解v_bound_func(si)的一阶导,

 

values[non_zero_index] = -1.0 * v_bound_func_.Evaluate(1, s);

s上下界松弛约束,2(np−1)个

si−sisoft_low_slack+silow_slack>=0.0, np−1 soft safety low boundary constraints

g[i]=si−sisoft_low_slack+silow_slack,i∈[5np,6np−1]

si−sisoft_upper_slack+siupper_slack>=0.0, np−1 soft safety upper boundary constraints

g[i]=si−sisoft_upper_slack+siupper_slack,i∈[6np,7np−1]

eval_h

• 变量值:·x· • 拉格朗日乘数:·lambda· • 黑塞矩阵值:·values· • 目标函数因数:·obj_factor·

 

bool PiecewiseJerkSpeedNonlinearIpoptInterface::eval_h( int n, const double *x, bool new_x, double obj_factor, int m, const double *lambda, bool new_lambda, int nele_hess, int *iRow, int *jCol, double *values)

黑塞矩阵Hession Matrix

H=[∂2f∂x12∂2f∂x1∂x2⋯∂2f∂x1∂xn∂2f∂x2∂x1∂2f∂x22⋯∂2f∂x2∂xn⋮⋮⋱⋮∂2f∂xn∂x1∂2f∂xn∂x2⋯∂2f∂xn2]

拉格朗日函数:

Ipopt的拉格朗日黑塞矩阵:

目标函数

f(s→)=wref−s⋅∑i=0n−1(si−s−refi)2+wref−v⋅∑i=0n−1(s˙i−v−ref)2+wa⋅∑i=0n−1s¨i2+wj⋅∑i=0n−2(s¨i+1−s¨ideltat)2+wc−a⋅∑i=0n−1(s˙i⋅s˙i∙ kappa i)2+wtar_s(xnp−1−xtar)2+wtar_v(x˙2∗np−2−vtar)2+wtar_a(x¨3∗np−3−atar)2+wsoft_s_low∑i=0n−1slow_slack+wsoft_s_upper∑i=0n−1supper_slack

约束

vmax∗dt>=si+1−si>=0.0, np−1 s monotone constraints

|s¨i+1−s¨i|/dt<=s⃛max, np−1 jerk bound constraint

si+1−si−s˙i∗dt−13∗s¨i∗dt2−16∗s¨i+1∗dt2=0, np−1 position equality constraints

s˙i+1−s˙i−12∗dt∗s¨i−12∗dt∗s¨i+1=0, np−1 velocity equality constraints

s˙i−v_bound_func_(si)<=0.0,,np−1speed limit constraints

si−sisoft_low_slack+silow_slack>=0.0, np−1 soft safety low boundary constraints

si−sisoft_upper_slack+siupper_slack>=0.0, np−1 soft safety upper boundary constraints

目标函数的二阶偏导数(推导略)

∂2f∂si2=2wref_s+2wlat_acc[s˙i4⋅(kappa′(si))2+s˙i4⋅kappa(si)⋅kappa′′(si)]

∂2f∂si∂si′=8wlat_accsi′3⋅kappa⁡(si)⋅kappa′(si)

∂2f∂si′2=12wlat_accsi′2⋅kappa2⁡(si)+2wref−v

∂2f∂si′′2=2wjdt2+2wa

约束函数的二阶偏导

∂2g∂si2=−v_bound_func′′(si)

同样是稀疏矩阵的存储形式,按照行列映射的value index进行塞值,值得注意的是hessen矩阵只需要塞下三角矩阵,这个映射是通过hessian_mapper_使用一个unordered_map实现的。需要注意的是传入的kappa(si),kappa′(si),kappa′′(si),v_bound_func′′(si)并非显式表达式, 而是传入函数。

下面塞的是目标函数中对横向加速度产生的二阶导,需要乘上目标函数因数obj_factor

2wlat_acc[s˙i4⋅(kappa′(si))2+s˙i4⋅kappa(si)⋅kappa′′(si)]

8wlat_accsi′3⋅kappa⁡(si)⋅kappa′(si)

12wlat_accsi′2⋅kappa2⁡(si)+2wref−v

 

// speed by curvature objective for (int i = 0; i < num_of_points_; ++i) { auto s_index = i; auto v_index = v_offset_ + i; auto s = x[s_index]; auto v = x[v_index]; auto kappa = curvature_curve_.Evaluate(0, s); auto kappa_dot = curvature_curve_.Evaluate(1, s); auto kappa_ddot = curvature_curve_.Evaluate(2, s); auto v2 = v * v; auto v3 = v2 * v; auto v4 = v3 * v; auto h_s_s_obj = 2.0 * kappa_dot * kappa_dot * v4 + 2.0 * kappa * kappa_ddot * v4; auto h_s_s_index = hessian_mapper_[to_hash_key(s_index, s_index)]; values[h_s_s_index] += h_s_s_obj * w_overall_centripetal_acc_ * obj_factor; auto h_s_v_obj = 8.0 * kappa * kappa_dot * v3; auto h_s_v_index = hessian_mapper_[to_hash_key(s_index, v_index)]; values[h_s_v_index] += h_s_v_obj * w_overall_centripetal_acc_ * obj_factor; auto h_v_v_obj = 12.0 * kappa * kappa * v2; auto h_v_v_index = hessian_mapper_[to_hash_key(v_index, v_index)]; values[h_v_v_index] += h_v_v_obj * w_overall_centripetal_acc_ * obj_factor; }

下面塞的是目标函数中位置偏差项产生的二阶导,需要乘上目标函数因数obj_factor

2wref_s

 

// spatial distance reference objective for (int i = 0; i < num_of_points_; ++i) { auto h_s_s_index = hessian_mapper_[to_hash_key(i, i)]; values[h_s_s_index] += 2.0 * w_ref_s_ * obj_factor; }

下面塞约束函数产生的二阶导数,需要乘上对应位置的拉格朗日因子lambda[i]

−v_bound_func′′(si)

 

int lambda_offset = 4 * (num_of_points_ - 1); for (int i = 0; i < num_of_points_; ++i) { auto s_index = i; auto s = x[s_index]; auto v_bound_ddot = v_bound_func_.Evaluate(2, s); auto h_s_s_constr = -1.0 * v_bound_ddot; auto h_s_s_index = hessian_mapper_[to_hash_key(s_index, s_index)]; values[h_s_s_index] += h_s_s_constr * lambda[lambda_offset + i]; }

下面塞的是目标函数中位置偏差项产生的二阶导,需要乘上目标函数因数obj_factor

2wref_a

 

for (int i = 0; i < num_of_points_; ++i) { auto a_index = a_offset_ + i; auto h_index = hessian_mapper_[to_hash_key(a_index, a_index)]; values[h_index] += 2.0 * w_overall_a_ * obj_factor; }

下面塞的是jerk项产生的二阶导,

2wjdt2 , 但是为什么这里对三个位置进行了填充,不就一个位置吗?但是为什么这里对三个位置进行了填充,不就一个位置吗?

 

auto c = 2.0 / delta_t_ / delta_t_ * w_overall_j_ * obj_factor; for (int i = 0; i + 1 < num_of_points_; ++i) { auto a0_index = a_offset_ + i; auto a1_index = a_offset_ + i + 1; auto h_a0_a0_index = hessian_mapper_[to_hash_key(a0_index, a0_index)]; values[h_a0_a0_index] += c; auto h_a0_a1_index = hessian_mapper_[to_hash_key(a0_index, a1_index)]; values[h_a0_a1_index] += -c; auto h_a1_a1_index = hessian_mapper_[to_hash_key(a1_index, a1_index)]; values[h_a1_a1_index] += c; }

下面塞又速度项产生的二阶导,

2wref−v

 

for (int i = 0; i < num_of_points_; ++i) { auto v_index = i + v_offset_; auto key = to_hash_key(v_index, v_index); auto index = hessian_mapper_[key]; values[index] += 2.0 * w_ref_v_ * obj_factor; }

如果有终端约束, 则由cost终端约束产生的二阶导,

 

if (has_end_state_target_) { // target s auto s_end_index = num_of_points_ - 1; auto s_key = to_hash_key(s_end_index, s_end_index); auto s_index = hessian_mapper_[s_key]; values[s_index] += 2.0 * w_target_s_ * obj_factor; // target v auto v_end_index = 2 * num_of_points_ - 1; auto v_key = to_hash_key(v_end_index, v_end_index); auto v_index = hessian_mapper_[v_key]; values[v_index] += 2.0 * w_target_v_ * obj_factor; // target a auto a_end_index = 3 * num_of_points_ - 1; auto a_key = to_hash_key(a_end_index, a_end_index); auto a_index = hessian_mapper_[a_key]; values[a_index] += 2.0 * w_target_a_ * obj_factor; }

get_optimization_results & finalize_solution

得到最终结果,并打印求解中间信息。最终输出的是最优的是

[s[0], s[1] ...s[np-1], | v[0], v[1] ...v[np-1] |,a[0], a[1] ...a[np-1]]

 

void PiecewiseJerkSpeedNonlinearIpoptInterface::get_optimization_results( std::vector<double> *ptr_opt_s, std::vector<double> *ptr_opt_v, std::vector<double> *ptr_opt_a) { *ptr_opt_s = opt_s_; *ptr_opt_v = opt_v_; *ptr_opt_a = opt_a_; } void PiecewiseJerkSpeedNonlinearIpoptInterface::finalize_solution( Ipopt::SolverReturn status, int n, const double *x, const double *z_L, const double *z_U, int m, const double *g, const double *lambda, double obj_value, const Ipopt::IpoptData *ip_data, Ipopt::IpoptCalculatedQuantities *ip_cq) { opt_s_.clear(); opt_v_.clear(); opt_a_.clear(); for (int i = 0; i < num_of_points_; ++i) { double s = x[i]; double v = x[v_offset_ + i]; double a = x[a_offset_ + i]; opt_s_.push_back(s); opt_v_.push_back(v); opt_a_.push_back(a); } }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hebastast

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值