自动驾驶规划中使用 OSQP 进行二次规划 代码原理详细解读

目录

1 问题描述

什么是稀疏矩阵 CSC 形式

QP Path Planning 问题

1. Cost function

1.1 The first term:

1.2 The second term:

1.3 The thrid term:

1.4 The forth term:

对 Qx''' 矩阵公式的验证

整体 Q 矩阵(就是 P 矩阵,二次项的权重矩阵)

整体 P 矩阵的形式如下:

目标函数中的线性项部分,即 q 矩阵的构建

计算 q 矩阵的代码块如下:

2. Constraints

2.1 不等式约束

2.2 连续性约束

Equality constraints

不等式约束的上下边界条件为:

上下边界条件是如何计算的?

二阶导边界极值的计算:

三阶导边界极值的计算

最后,A 矩阵为:

仿射矩阵 A


1 问题描述

典型的优化问题可以用以下的数学表达式来描述:

其中,P 是一个 n x n 的半正定矩阵, x 为 n 维向量,q 为 m x n 的矩阵。

需要注意的是,二次规划只在代价函数为凸函数的时候能够收敛到最优解,因此这需要 P 矩阵为半正定矩阵,这是非常重要的一个条件。这反映在 Apollo 中的规划算法则为需要进行求解的空间为凸空间,这样二次规划才能收敛到一条最优 Path。

上面的表述源自:Apollo 二次规划算法(piecewise jerk path optimizer)解析

什么是半正定矩阵?什么是正定矩阵?

设 A 为实对称矩阵,若对于每个非零实向量 X,都有 X'AX ≥ 0,则称 A 为半正定矩阵,称 X'AX 为半正定二次型。(其中,X'表示 X 的转置。)

注 :

在 OSQP 中,对上述的数据用结构体 OSQPData 进行封装,其定义如下:

// the location of file: /usr/local/include/osqp/types.h

typedef struct {

c_int n; ///< number of variables n

c_int m; ///< number of constraints m

csc *P; ///< the upper triangular part of the quadratic cost matrix P

csc *A; ///< linear constraints matrix A in csc format (size m x n)

c_float *q; ///< dense array for linear part of cost function (size n)

c_float *l; ///< dense array for lower bound (size m)

c_float *u; ///< dense array for upper bound (size m)

} OSQPData;

其中,P 和 A 都是以稀疏矩阵 CSC 的形式进行存储的。

什么是稀疏矩阵 CSC 形式

CSC - Compressed sparse column (CSC or CCS)

稀疏矩阵和稠密矩阵 - 看矩阵中非零元素占所有元素的比例

在矩阵中,若数值为 0 的元素数目远远多于非 0 元素的数目,并且非 0 元素分布没有规律时,则称该矩阵为稀疏矩阵;与之相反,若非 0 元素数目占大多数时,则称该矩阵为稠密矩阵。定义非零元素的总数比上矩阵所有元素的总数为矩阵的稠密度。

稀疏矩阵的常规方式

下面是最常见的一种,也很好理解,(row,col) 指向矩阵非零元素的索引,data 里为该元素的值。

稀疏矩阵的 CSC 形式 - csc_matrix

按列压缩 Compressed sparse column,顾名思义将每一列出现的非零元素的个数统计后放好。

如何保证规划算法求解的空间为凸空间?

QP Path Planning 问题

QP 问题的标准形式(下面是常见的两种表示方法):

1. Cost function

论文中的 cost 函数实际上是如下的形式:

优化变量的形式是:

Cost function 也可以写成下面这种形式:

我们注意到第一项和第二项的内容似乎相同,但其实是有所区别的。我们通过下图来解释。

可以看到,我们要规划的离散点曲线是在 SL 坐标系下进行的。所以第一项惩罚的横向偏移也就是偏移 s 的法向的距离,可以理解为关于车道中心线的偏移。而第四项关于参考线的偏移,则是考虑了静态和低速障碍物生成的一条参考线,第四项所计算的偏移其实是关于参考线的偏移。我们可以这样理解这两项:我们规划的最优轨迹要尽量贴合原来的车道中心线,同时还要尽量贴合能够避障的参考线。

1.1 The first term:

一共有 n 个点:

假如有四个点需要优化,为 x0, x1, ... x3,则矩阵为:

1.2 The second term:

1.3 The thrid term:

1.4 The forth term:

对 Qx''' 矩阵公式的验证

假设有四个点,x1, x2... x3,则:

使用上面的 matrix form:

说明上述的 Qx''' 的公式是正确的。

整体 Q 矩阵(就是 P 矩阵,二次项的权重矩阵)

所以,cost function 的 Q 矩阵为:

整体 P 矩阵的形式如下:
 

注意:代码中 Apollo 中的 Q 矩阵(代码中是 P 矩阵)形式与上述推导有一定的差异:

Apollo 6.0 代码中的 P 矩阵形式如下:

参见这篇文章:

https://zhuanlan.zhihu.com/p/480298921

目标函数的形式如下:

下面就是代码中的 P 矩阵的实际形式:

构建 P 矩阵的函数:

void PiecewiseJerkPathProblem::CalculateKernel(std::vector<c_float>* P_data,

                                               std::vector<c_int>* P_indices,

                                               std::vector<c_int>* P_indptr)

P 矩阵的零阶导数(蓝色)部分对应的代码块:

// x(i)^2 * (w_x + w_x_ref[i]), w_x_ref might be a uniform value for all x(i)

  // or piecewise values for different x(i)

  // P 矩阵的零阶导数部分

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

    columns[i].emplace_back(i, (weight_x_ + weight_x_ref_vec_[i]) /

                                   (scale_factor_[0] * scale_factor_[0])); // scale_factor - 缩放系数

    ++value_index;

  }

  // x(n-1)^2 * (w_x + w_x_ref[n-1] + w_end_x) - 最后一个节点增加了一个末状态的权重 w_end_x

  columns[n - 1].emplace_back(

      n - 1, (weight_x_ + weight_x_ref_vec_[n - 1] + weight_end_state_[0]) /

                 (scale_factor_[0] * scale_factor_[0]));

  ++value_index;

P 矩阵的一阶导数(粉色)部分对应的代码块:

  // x(i)'^2 * w_dx - P 矩阵的一阶导数部分

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

    columns[n + i].emplace_back(

        n + i, weight_dx_ / (scale_factor_[1] * scale_factor_[1]));

    ++value_index;

  }

  // x(n-1)'^2 * (w_dx + w_end_dx)

  columns[2 * n - 1].emplace_back(2 * n - 1,

                                  (weight_dx_ + weight_end_state_[1]) /

                                      (scale_factor_[1] * scale_factor_[1]));

  ++value_index;

P 矩阵的二阶导数(绿色)部分对应的代码块:

 auto delta_s_square = delta_s_ * delta_s_;

  // P 矩阵的二阶导数部分的第一个对角线元素

  // x(i)''^2 * (w_ddx + 2 * w_dddx / delta_s^2)

  columns[2 * n].emplace_back(2 * n,

                              (weight_ddx_ + weight_dddx_ / delta_s_square) /

                                  (scale_factor_[2] * scale_factor_[2]));

  ++value_index;

  // P 矩阵的二阶导数部分的对角线元素(除了对角线上的第一个元素和最后一个元素)

  for (int i = 1; i < n - 1; ++i) {

    columns[2 * n + i].emplace_back(

        2 * n + i, (weight_ddx_ + 2.0 * weight_dddx_ / delta_s_square) /

                       (scale_factor_[2] * scale_factor_[2]));

    ++value_index;

  }

  // P 矩阵的二阶导数部分的最后一个对角线元素

  columns[3 * n - 1].emplace_back(

      3 * n - 1,

      (weight_ddx_ + weight_dddx_ / delta_s_square + weight_end_state_[2]) /

          (scale_factor_[2] * scale_factor_[2]));

  ++value_index;

  // P 矩阵的二阶导数部分的次对角线上的元素

  // -2 * w_dddx / delta_s^2 * x(i)'' * x(i + 1)''

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

    columns[2 * n + i].emplace_back(2 * n + i + 1,

                                    (-2.0 * weight_dddx_ / delta_s_square) /

                                        (scale_factor_[2] * scale_factor_[2]));

    ++value_index;

目标函数中的线性项部分,即 q 矩阵的构建

这部分代码在 PiecewiseJerkPathProblem::CalculateOffset 这个函数

void PiecewiseJerkPathProblem::CalculateOffset(std::vector<c_float>* q)

q 矩阵形式如下:

计算 q 矩阵的代码块如下:

  if (has_x_ref_) {

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

      q->at(i) += -2.0 * weight_x_ref_vec_.at(i) * x_ref_[i] / scale_factor_[0];

    }

  }

  //

  if (has_end_state_ref_) {

    q->at(n - 1) +=

        -2.0 * weight_end_state_[0] * end_state_ref_[0] / scale_factor_[0];

    q->at(2 * n - 1) +=

        -2.0 * weight_end_state_[1] * end_state_ref_[1] / scale_factor_[1];

    q->at(3 * n - 1) +=

        -2.0 * weight_end_state_[2] * end_state_ref_[2] / scale_factor_[2];

  }

2. Constraints

2.1 不等式约束

2.2 连续性约束

用每个轨迹点处在 l 方向的 jerk 相等作为连续性约束。

上面的推导和下面的推导是一致的:

将 piecewise jerk 的条件带入:

得:

Now we generate constraints in matrix form.

For constrains a - lateral offset - 0 阶导数

For constrains b - lateral velocity - 一阶导数

For constrains c - lateral acceleration - 二阶导

For constraints d - lateral jerk - 三阶导数

这里有一些问题,对于 jerk 的不等式约束,应该是下面的形式:

For constraints e - 连续性约束

下图是有四个点的时候仿射矩阵的具体形式:

For Constraints f:

约束可以写成:

具体形式:

Equality constraints

不等式约束的上下边界条件为:

上下边界条件是如何计算的?

关于边界约束的详细介绍参见这篇文章:https://zhuanlan.zhihu.com/p/481835121

二阶导边界极值的计算:

对应代码如下:

const double lat_acc_bound =

std::tan(veh_param.max_steer_angle() / veh_param.steer_ratio()) /

veh_param.wheel_base();

std::vector<std::pair<double, double>> ddl_bounds;

for (size_t i = 0; i < path_boundary_size; ++i) {

double s = static_cast<double>(i) * path_boundary.delta_s() +

path_boundary.start_s();

double kappa = reference_line.GetNearestReferencePoint(s).kappa();

ddl_bounds.emplace_back(-lat_acc_bound - kappa, lat_acc_bound - kappa);

}

三阶导边界极值的计算

最后,A 矩阵为:

仿射矩阵 A

至此,P 矩阵,q 矩阵,A 矩阵,b 矩阵均可以表示出来,放入 OSQP 求解器中,可以进行迭代求解了。

The Principle of Apollo Path Planning using Quadratic Programming

这里是 Piecewise Jerk Path Optimizer 的代码讲解。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据库】六、事务与并发控制(封锁)

六、事务与并发控制 文章目录 六、事务与并发控制1.事务1.1事务的ACID特性1.2MySQL事务控制语句开启事务提交事务回滚事务 2.并发控制2.1并发执行可能引起的问题2.1.1丢失更新2.1.2不可重复读2.1.3读脏数据 2.2并发调度的可串行性2.3并发与并行的区分2.4事务的隔离级别 3.封锁3…

36.Http协议的设计与解析

Http协议比Redis协议复杂的多,如果程序员自己去实现,工作量大。 Netty已经把Http协议的编解码器实现好了,只需要简单的配置就可以使用。 做一个http的服务端需要HttpServerCodec。 看它继承的父类: 结合了两个类: HttpRequestDecoder(入站处理器extends Channelnbound…

数据库的概念-数据库、数据库管理系统、数据库系统、数据库管理员、数据库设计人员、开发管理使用数据库系统的人员

一、数据库&#xff08;DB&#xff09; 1、数据库就是存储数据的仓库&#xff0c;只不过这个仓库是在计算机存储设备上 2、严格的说&#xff0c;数据库是长期存储在计算机内、有组织的、统一管理的、可共享的相关数据的集合 3、数据库应是为一个特定目标而设计、构建并装入数…

PriorityQueue详解(含动画演示)

目录 PriorityQueue详解1、PriorityQueue简介2、PriorityQueue继承体系3、PriorityQueue数据结构PriorityQueue类属性注释完全二叉树、大顶堆、小顶堆的概念☆PriorityQueue是如何利用数组存储小顶堆的&#xff1f;☆利用数组存储完全二叉树的好处&#xff1f; 4、PriorityQueu…

酒店宾馆民宿预订管理系统(ThinkPHP+uniapp+uView)

便捷高效&#xff0c;轻松管理你的住宿预订&#x1f3e8; 基于ThinkPHPuniappuView开发的多门店民宿酒店预订管理系统&#xff0c;快速部署属于自己民宿酒店的预订小程序&#xff0c;包含预订、退房、WIFI连接、吐槽、周边信息等功能。​​ 一、引言&#xff1a;为何需要民宿…

Spring Boot+vue社区养老系统(智慧养老平台)

使用技术&#xff1a; springbootvueMySQL 主要功能&#xff1a; 管理员 登录个人资料密码管理, 用户管理:床位类型管理,床位管理,护工管理,老人管理 咨询登记管理&#xff0c;预约登记管理,老人健康信 息管理,费用管理等功能.护工角色包含以下功能: 护工登录&#xff0c;个…

使用 GCD 实现属性的多读单写

使用 Grand Central Dispatch (GCD) 实现多读单写的属性 首先需要确保在多线程环境下的线程安全性。可以使用 GCD 提供的读写锁机制 dispatch_rwlock_t 或者 dispatch_queue_t 来实现这个功能。 Swift版本的实现 怎样创建一个并发队列 &#xff1f;// 使用 Swift 来实现的首…

UE5 中的碰撞问题

文章目录 一、初始准备二、重叠和碰撞三、自定义碰撞 一、初始准备 首先我们创建一个 BP_ThirdPerson 项目&#xff0c;然后在项目中创建两个 Actor 的蓝图 Blueprint 首先是一个移动的 BP_Push&#xff0c;这里使用 time line 循环旋转 cube 的相对位置 得到效果如下 然后是…

css如何动态累计数字?

导读&#xff1a;css如何动态累计数字&#xff1f;用于章节目录的序列数生成&#xff0c;用css的计数器实现起来比 js方式更简单&#xff01; 伪元素 ::after ::before伪元素设置content 可以在元素的首部和尾部添加内容&#xff0c;我们要在元素的首部添加序列号&#xff0c…

关于read,write,open时出现的文本文件和二进制文件读写的问题(怎么写入怎么读)

1、发现问题 使用read读取文本文件&#xff0c;一般采用字符空间作为缓存&#xff0c;最后输出&#xff1b; 使用read读取二进制文件&#xff0c;这里采用整数读取的展示&#xff1a; 首先创建文本文件&#xff0c;用write写入i的值到文件中&#xff1b; 再通过lseek改变读写一…

Day9 —— 大数据技术之ZooKeeper

ZooKeeper快速入门系列 ZooKeeper的概述什么是ZooKeeper&#xff1f;ZooKeeper的特点和功能使用ZooKeeper的原因 ZooKeeper数据模型ZooKeeper安装ZooKeeper配置ZooKeeper命令行操作常见服务端命令 ZooKeeper的概述 什么是ZooKeeper&#xff1f; ZooKeeper是一个开源的分布式协…

FFmpeg编译4

CPUx86-64 TOOLCHAIN N D K / t o o l c h a i n s / x 8 6 6 4 − 4.9 / p r e b u i l t / l i n u x − x 8 6 6 4 S Y S R O O T NDK/toolchains/x86_64-4.9/prebuilt/linux-x86_64 SYSROOT NDK/toolchains/x866​4−4.9/prebuilt/linux−x866​4SYSROOTNDK/platforms/and…

PBR网络数据流量分流+NQA联动静态路由

一、实验目的&#xff1a; 企业有两个网段&#xff0c;业务1网段和业务2网段&#xff0c;拓扑图如下&#xff0c; 二、实验要求 pc1报文走左侧链路到达ar1&#xff0c;pc2报文走右侧链路到达ar1&#xff0c;且当ar2或者ar3发生故障时候&#xff0c;可以通过另一个设备到达ar1…

HCIA 19 结束 企业总部-分支综合实验(下)

3.6出口NAT配置可以访问互联网 配置NAT使内网可以访问公网8.8.8.8&#xff0c;当前总部PC1 PING不通公网地址8.8.8.8。 3.6.1总部配置NAT访问互联网 步骤1&#xff1a;配置NAT acl number 2000 rule 5 permit source 192.168.0.0 0.0.255.255 # interface GigabitEthern…

头条系统-05-延迟队列精准发布文章-概述添加任务(db和redis实现延迟任务)、取消拉取任务定时刷新(redis管道、分布式锁setNx)

文章目录 延迟任务精准发布文章1)文章定时发布2)延迟任务概述2.1)什么是延迟任务2.2)技术对比2.2.1)DelayQueue2.2.2)RabbitMQ实现延迟任务2.2.3)redis实现 3)redis实现延迟任务4)延迟任务服务实现4.1)搭建heima-leadnews-schedule模块4.2)数据库准备4.3)安装redis4.4)项目集成…

常用加密算法之 RSA 简介及应用

引言 相关博文&#xff1a; Spring Boot 开发 – 常用加密算法简介&#xff08;一&#xff09;常用加密算法之 SM4 简介及应用 一、RSA算法简介 RSA &#xff08;Rivest-Shamir-Adleman&#xff09; 算法是一种非对称加密技术&#xff0c;由Ron Rivest、Adi Shamir和Leonar…

基于动力学的六自由度机器人阻抗恒力跟踪控制

1.整个代码的控制流程图如下&#xff1a; 2.正逆运动学计算 略 3.动力学模型 采用拉格朗日法计算机械臂的动力学模型&#xff0c;其输入的是机械臂的关节角度、角速度和角加速度&#xff1b;其中M、C、G本别是计算的惯性力、科式力和重力项&#xff0c;相关部分如下&#xf…

【fastapi+mongodb】使用motor操作mongodb(三)

本篇文章介绍mongodb的删和改&#xff0c;下面是前两篇文章的链接&#xff1a; 【fastapimongodb】使用motor操作mongodb 【fastapimongodb】使用motor操作mongodb&#xff08;二&#xff09; delete delete 的用法基本和查找一致&#xff0c;包括delete_one&#xff08;删除…

某大厂程序员吐槽:离职交接时,新人被工作量吓退,领导却污蔑我故意劝退新人,我怒晒工作短信反击证明,新人看了后也决定走人了!

一位知名大公司的程序员分享了他离职时的遭遇&#xff1a;在交接工作时&#xff0c;新进的同事因工作量过大而感到压力&#xff0c;但出乎意料的是&#xff0c;他们的领导却指责我故意吓唬新人。为了证明自己的清白&#xff0c;我晒出了工作短信作为反击&#xff0c;结果连新人…

Vue71-嵌套(多级)路由

一、需求 二、开发步骤 2-1、编写路由组件 2-2、编写路由规则 2-3、编写路由标签<router-link>、<router-view> 三、小结