曲线生成 | 图解B样条曲线生成原理(附ROS C++/Python/Matlab仿真)

目录

  • 0 专栏介绍
  • 1 控制点计算之插值
  • 2 控制点计算之近似
  • 3 仿真实现
    • 3.1 ROS C++实现
    • 3.2 Python实现
    • 3.3 Matlab实现

0 专栏介绍

🔥附C++/Python/Matlab全套代码🔥课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);曲线优化(贝塞尔曲线、B样条曲线等)。

🚀详情:图解自动驾驶中的运动规划(Motion Planning),附几十种规划算法


在曲线生成 | 图解B样条曲线生成原理(基本概念与节点生成算法)中,我们介绍了B样条曲线的基本概念,例如基函数的递推、曲线支撑性原理、节点生成公式等。本文进一步计算控制点计算和曲线生成原理。

1 控制点计算之插值

设B样条曲线为

P ( t ) = ∑ i = 0 n − 1 p i N i , k ( t ) \boldsymbol{P}\left( t \right) =\sum_{i=0}^{n-1}{\boldsymbol{p}_iN_{i,k}\left( t \right)} P(t)=i=0n1piNi,k(t)

其中 p i \boldsymbol{p}_i pi是待求的控制节点。令参数向量满足其映射为数据点

D j = P ( u j ) = ∑ i = 0 n − 1 p i N i , k ( u j ) , j = 0 , 1 , ⋯   , n − 1 \boldsymbol{D}_j=\boldsymbol{P}\left( u_j \right) =\sum_{i=0}^{n-1}{\boldsymbol{p}_iN_{i,k}\left( u_j \right)}, j=0,1,\cdots ,n-1 Dj=P(uj)=i=0n1piNi,k(uj),j=0,1,,n1

这里 N N N个数据点可求解出 N N N个控制点,所以 n = N n=N n=N,可以矩阵化为

D = N P \boldsymbol{D}=\boldsymbol{NP} D=NP

其中

D = [ d 0 T d 1 T ⋮ d n − 1 T ] , P = [ p 0 T p 1 T ⋮ p n − 1 T ] , N = [ N 0 , k ( u 0 ) N 1 , k ( u 0 ) ⋯ N n − 1 , k ( u 0 ) N 0 , k ( u 1 ) N 1 , k ( u 1 ) ⋯ N n − 1 , k ( u 1 ) ⋮ ⋮ ⋱ ⋮ N 0 , k ( u n − 1 ) N 1 , k ( u n − 1 ) ⋯ N n − 1 , k ( u n − 1 ) ] \boldsymbol{D}=\left[ \begin{array}{c} \boldsymbol{d}_{0}^{T}\\ \boldsymbol{d}_{1}^{T}\\ \vdots\\ \boldsymbol{d}_{n-1}^{T}\\\end{array} \right] , \boldsymbol{P}=\left[ \begin{array}{c} \boldsymbol{p}_{0}^{T}\\ \boldsymbol{p}_{1}^{T}\\ \vdots\\ \boldsymbol{p}_{n-1}^{T}\\\end{array} \right] , \boldsymbol{N}=\left[ \begin{matrix} N_{0,k}\left( u_0 \right)& N_{1,k}\left( u_0 \right)& \cdots& N_{n-1,k}\left( u_0 \right)\\ N_{0,k}\left( u_1 \right)& N_{1,k}\left( u_1 \right)& \cdots& N_{n-1,k}\left( u_1 \right)\\ \vdots& \vdots& \ddots& \vdots\\ N_{0,k}\left( u_{n-1} \right)& N_{1,k}\left( u_{n-1} \right)& \cdots& N_{n-1,k}\left( u_{n-1} \right)\\\end{matrix} \right] D= d0Td1Tdn1T ,P= p0Tp1Tpn1T ,N= N0,k(u0)N0,k(u1)N0,k(un1)N1,k(u0)N1,k(u1)N1,k(un1)Nn1,k(u0)Nn1,k(u1)Nn1,k(un1)

求解该方程即可得到控制点。

2 控制点计算之近似

在插值问题中,插值曲线可能会在数据点间波动,而非紧密遵循数据多边形。为克服这个问题,可以放宽曲线必须穿过所有数据点的硬约束。除了第一个和最后一个数据点,曲线不必包含任何其他点,通过约束最小二乘误差来实现最优近似。考虑到节点向量中首末节点重复度为 k + 1 k+1 k+1时,B样条曲线穿过首末控制点,所以令 p 0 = d 0 \boldsymbol{p}_{0}=\boldsymbol{d}_{0} p0=d0 p n − 1 = d n − 1 \boldsymbol{p}_{n-1}=\boldsymbol{d}_{n-1} pn1=dn1,则

P ( t ) = N 0 , k ( t ) p 0 + ∑ i = 1 n − 2 p i N i , k ( t ) + N n − 1 , k ( t ) p n − 1 \boldsymbol{P}\left( t \right) =N_{0,k}\left( t \right) \boldsymbol{p}_0+\sum_{i=1}^{n-2}{\boldsymbol{p}_iN_{i,k}\left( t \right)}+N_{n-1,k}\left( t \right) \boldsymbol{p}_{n-1} P(t)=N0,k(t)p0+i=1n2piNi,k(t)+Nn1,k(t)pn1

从而可以计算最小二乘误差

f ( p 1 , p 2 , ⋯   , p n − 2 ) = ∑ i = 1 n − 2 [ d i − P ( u i ) ] 2 = ∑ i = 1 n − 2 [ ( d i − N 0 , k ( u i ) p 0 − N n − 1 , k ( u i ) p n − 1 ) ⏟ q i − ∑ j = 1 n − 2 p j N j , k ( u i ) ] 2 = ∑ i = 1 n − 2 [ q i T q i − 2 q i ∑ j = 1 n − 2 p j N j , k ( u i ) + ∑ j = 1 n − 2 p j N j , k ( u i ) ∑ j = 1 n − 2 p j N j , k ( u i ) ] \begin{aligned}f\left( \boldsymbol{p}_1,\boldsymbol{p}_2,\cdots ,\boldsymbol{p}_{n-2} \right) &=\sum_{i=1}^{n-2}{\left[ \boldsymbol{d}_i-\boldsymbol{P}\left( u_i \right) \right] ^2}\\&=\sum_{i=1}^{n-2}{\left[ \underset{{ \boldsymbol{q}_i}}{\underbrace{\left( \boldsymbol{d}_i-N_{0,k}\left( u_i \right) \boldsymbol{p}_0-N_{n-1,k}\left( u_i \right) \boldsymbol{p}_{n-1} \right) }}-\sum_{j=1}^{n-2}{\boldsymbol{p}_jN_{j,k}\left( u_i \right)} \right] ^2}\\&=\sum_{i=1}^{n-2}{\left[ \boldsymbol{q}_{i}^{T}\boldsymbol{q}_i-2\boldsymbol{q}_i\sum_{j=1}^{n-2}{\boldsymbol{p}_jN_{j,k}\left( u_i \right)}+\sum_{j=1}^{n-2}{\boldsymbol{p}_jN_{j,k}\left( u_i \right)}\sum_{j=1}^{n-2}{\boldsymbol{p}_jN_{j,k}\left( u_i \right)} \right]}\end{aligned} f(p1,p2,,pn2)=i=1n2[diP(ui)]2=i=1n2 qi (diN0,k(ui)p0Nn1,k(ui)pn1)j=1n2pjNj,k(ui) 2=i=1n2[qiTqi2qij=1n2pjNj,k(ui)+j=1n2pjNj,k(ui)j=1n2pjNj,k(ui)]

将误差函数对 p g ( g = 1 , 2 , ⋯   , n − 2 ) \boldsymbol{p}_g\left( g=1,2,\cdots ,n-2 \right) pg(g=1,2,,n2)求偏导,可得

∂ f ( p 1 , p 2 , ⋯   , p n − 2 ) ∂ p g = ∑ i = 1 n − 2 [ − 2 q i N g , k ( u i ) + 2 N g , k ( u i ) ∑ j = 1 n − 2 p j N j , k ( u i ) ] \frac{\partial f\left( \boldsymbol{p}_1,\boldsymbol{p}_2,\cdots ,\boldsymbol{p}_{n-2} \right)}{\partial \boldsymbol{p}_g}=\sum_{i=1}^{n-2}{\left[ -2\boldsymbol{q}_iN_{g,k}\left( u_i \right) +2N_{g,k}\left( u_i \right) \sum_{j=1}^{n-2}{\boldsymbol{p}_jN_{j,k}\left( u_i \right)} \right]} pgf(p1,p2,,pn2)=i=1n2[2qiNg,k(ui)+2Ng,k(ui)j=1n2pjNj,k(ui)]

∂ f ( p 1 , p 2 , ⋯   , p n − 2 ) / ∂ p g = 0 {{\partial f\left( \boldsymbol{p}_1,\boldsymbol{p}_2,\cdots ,\boldsymbol{p}_{n-2} \right)}/{\partial \boldsymbol{p}_g}}=0 f(p1,p2,,pn2)/pg=0可得

∑ i = 1 n − 2 [ ∑ j = 1 n − 2 N g , k ( u i ) N j , k ( u i ) ] p j = ∑ i = 1 n − 2 q i N g , k ( u i ) \sum_{i=1}^{n-2}{\left[ \sum_{j=1}^{n-2}{N_{g,k}\left( u_i \right) N_{j,k}\left( u_i \right)} \right] \boldsymbol{p}_j}=\sum_{i=1}^{n-2}{\boldsymbol{q}_iN_{g,k}\left( u_i \right)} i=1n2[j=1n2Ng,k(ui)Nj,k(ui)]pj=i=1n2qiNg,k(ui)

改写为矩阵形式

( N T N ) P = Q \left( \boldsymbol{N}^T\boldsymbol{N} \right) \boldsymbol{P}=\boldsymbol{Q} (NTN)P=Q

其中

P = [ p 1 T p 2 T ⋮ p n − 2 T ] , Q = [ ∑ i = 1 n − 2 q i N 1 , k ( u i ) ∑ i = 1 n − 2 q i N 2 , k ( u i ) ⋮ ∑ i = 1 n − 2 q i N n − 2 , k ( u i ) ] , N = [ N 1 , k ( u 1 ) N 2 , k ( u 1 ) ⋯ N n − 2 , k ( u 1 ) N 1 , k ( u 2 ) N 2 , k ( u 2 ) ⋯ N n − 2 , k ( u 2 ) ⋮ ⋮ ⋱ ⋮ N 1 , k ( u n − 2 ) N 2 , k ( u n − 2 ) ⋯ N n − 2 , k ( u n − 2 ) ] \boldsymbol{P}=\left[ \begin{array}{c} \boldsymbol{p}_{1}^{T}\\ \boldsymbol{p}_{2}^{T}\\ \vdots\\ \boldsymbol{p}_{n-2}^{T}\\\end{array} \right] , \boldsymbol{Q}=\left[ \begin{array}{c} \sum_{i=1}^{n-2}{\boldsymbol{q}_iN_{1,k}\left( u_i \right)}\\ \sum_{i=1}^{n-2}{\boldsymbol{q}_iN_{2,k}\left( u_i \right)}\\ \vdots\\ \sum_{i=1}^{n-2}{\boldsymbol{q}_iN_{n-2,k}\left( u_i \right)}\\\end{array} \right] , \boldsymbol{N}=\left[ \begin{matrix} N_{1,k}\left( u_1 \right)& N_{2,k}\left( u_1 \right)& \cdots& N_{n-2,k}\left( u_1 \right)\\ N_{1,k}\left( u_2 \right)& N_{2,k}\left( u_2 \right)& \cdots& N_{n-2,k}\left( u_2 \right)\\ \vdots& \vdots& \ddots& \vdots\\ N_{1,k}\left( u_{n-2} \right)& N_{2,k}\left( u_{n-2} \right)& \cdots& N_{n-2,k}\left( u_{n-2} \right)\\\end{matrix} \right] P= p1Tp2Tpn2T ,Q= i=1n2qiN1,k(ui)i=1n2qiN2,k(ui)i=1n2qiNn2,k(ui) ,N= N1,k(u1)N1,k(u2)N1,k(un2)N2,k(u1)N2,k(u2)N2,k(un2)Nn2,k(u1)Nn2,k(u2)Nn2,k(un2)

求解该方程即可得到控制点。

3 仿真实现

3.1 ROS C++实现

核心代码如下所示:

Points2d BSpline::interpolation(const Points2d points, const std::vector<double> param, const std::vector<double> knot)
{
  size_t n = points.size();
  Eigen::MatrixXd N = Eigen::MatrixXd::Zero(n, n);
  Eigen::MatrixXd D(n, 2);

  for (size_t i = 0; i < n; i++)
    for (size_t j = 0; j < n; j++)
      N(i, j) = baseFunction(j, order_, param[i], knot);
  N(n - 1, n - 1) = 1;

  for (size_t i = 0; i < n; i++)
  {
    D(i, 0) = points[i].first;
    D(i, 1) = points[i].second;
  }

  Eigen::MatrixXd C = N.inverse() * D;

  std::vector<std::pair<double, double>> control_points(n);

  for (size_t i = 0; i < n; i++)
    control_points[i] = { C(i, 0), C(i, 1) };

  return control_points;
}

3.2 Python实现

核心代码如下所示:

def approximation(self, points: list, param: list, knot: list):
	n = len(points)
	D = np.array(points)
	
	# heuristically setting the number of control points
	h = n - 1
	
	N = np.zeros((n, h))
	for i in range(n):
	    for j in range(h):
	        N[i][j] = self.baseFunction(j, self.k, param[i], knot)
	N_ = N[1 : n - 1, 1 : h - 1]
	
	qk = np.zeros((n - 2, 2))
	for i in range(1, n - 1):
	    qk[i - 1] = D[i, :] - N[i][0] * D[0, :] - N[i][h - 1] * D[-1, :]
	Q = N_.T @ qk
	
	P = np.linalg.inv(N_.T @ N_) @ Q
	P = np.insert(P, 0, D[0, :], axis=0)
	P = np.insert(P, len(P), D[-1, :], axis=0)
	
	return P

在这里插入图片描述

3.3 Matlab实现

核心代码如下所示:

function points = generation(knot, control_pts, param)
  n = ceil(1.0 / param.step);
  t = (0 : n - 1) / (n - 1);

  [m, ~] = size(control_pts);
  N = zeros(n, m);

  for i=1:n
    for j=1:m
      N(i, j) = baseFunction(j, param.order, t(i), knot);
    end
  end
  
  N(n, m) = 1.0;

  points = N * control_pts;
end

在这里插入图片描述

完整工程代码请联系下方博主名片获取


🔥 更多精彩专栏

  • 《ROS从入门到精通》
  • 《Pytorch深度学习实战》
  • 《机器学习强基计划》
  • 《运动规划实战精讲》

👇源码获取 · 技术交流 · 抱团学习 · 咨询分享 请联系👇

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

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

相关文章

990-11产品经理:Team Building in Project Management 项目管理中的团队建设

Introduction One of the most important developments in management during the 1970’s has been the widespread application广泛应用 of project teams to a variety of complex tasks. Project managers quickly learn the critical significance批判意义 of the effect…

Android RecyclerView 如何展示自定义列表 Kotlin

Android RecyclerView 如何展示自定义列表 Kotlin 一、前提 有这么一个对象 class DeviceDemo (val name: String, val type: String, val address: String)要展示一个包含这个对象的列表 bluetoothDevices.add(DeviceDemo("bb 9800", "LE", "32:…

Qt QWiget 实现简约美观的加载动画 第三季

&#x1f603; 第三季来啦 &#x1f603; 这是最终效果: 只有三个文件,可以直接编译运行 //main.cpp #include "LoadingAnimWidget.h" #include <QApplication> #include <QVBoxLayout> #include <QGridLayout> int main(int argc, char *argv[]…

《Docker 简易速速上手小册》第8章 Docker 在企业中的应用(2024 最新版)

文章目录 8.1 Docker 在开发环境中的应用8.1.1 重点基础知识8.1.2 重点案例&#xff1a;Python Web 应用开发环境8.1.3 拓展案例 1&#xff1a;Python 数据分析环境8.1.4 拓展案例 2&#xff1a;Python 自动化测试环境 8.2 Docker 在生产环境的实践8.2.1 重点基础知识8.2.2 重点…

R语言在生态环境领域中的应用

R语言作为新兴的统计软件&#xff0c;以开源、自由、免费等特点风靡全球。生态环境领域研究内容广泛&#xff0c;数据常多样而复杂。利用R语言进行多元统计分析&#xff0c;从复杂的现象中发现规律、探索机制正是R的优势。为此&#xff0c;本课程以鱼类、昆虫、水文、地形等多样…

精品基于springboot健身房管理系统-教练会员卡管理

《[含文档PPT源码等]精品基于springboot健身房管理系统[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; Java——涉及技术&#xff1a; 前端使用技术&#xff1a;HTML5,CS…

异常统一处理:Exception(兜底异常)

一、引言 本篇内容是“异常统一处理”系列文章的重要组成部分&#xff0c;主要聚焦于对 Exception&#xff08;兜底异常&#xff09; 的原理解析与异常处理机制&#xff0c;并给出测试案例。 关于 全局异常统一处理 的原理和完整实现逻辑&#xff0c;请参考文章&#xff1a; 《…

docker搭建zookeeper集群

文章目录 1. 集群搭建2. Leader选举3. Zookeeper集群角色 1. 集群搭建 这里我们使用docker-compose 搭建伪集群 version: 3.1 services:zoo1:image: zookeeperrestart: alwayscontainer_name: zoo1ports:- 2181:2181volumes:- /home/zk/zoo1/data:/data- /home/zk/zoo1/datal…

【数据结构初阶 7】二叉树:链式二叉树的基本操作实现

文章目录 &#x1f308; Ⅰ 定义二叉树结点&#x1f308; Ⅱ 创建二叉树结点&#x1f308; Ⅲ 遍历二叉树1. 先序遍历2. 中序遍历3. 后序遍历4. 层序遍历 &#x1f308; Ⅳ 销毁二叉树 &#x1f308; Ⅰ 定义二叉树结点 1. 每个结点都由三部分组成 数据域&#xff1a;存储本结…

【JVM】线上一次fullGC排查思路

fullGC问题背景 监控告警发现&#xff0c;今天开始我们线上应用频繁出现fullGC&#xff0c;并且每次出现后磁盘都会被占满 查看监控 查看监控发现FULLGC的机器均为同一个机房的集器&#xff0c;并且该机房有线上error报错&#xff0c;数据库监控对应的时间点也有异常&#x…

Vue3 路由配置 + 路由跳转 + 路由传参(动态路由传参 + 普通路由传参)

Vue Router&#xff1a; Vue.js 的官方路由。它与 Vue.js 核心深度集成&#xff0c;让用 Vue.js 构建单页应用变得轻而易举。 效果 一、介绍 1、官方文档&#xff1a;https://router.vuejs.org/zh/introduction.html 介绍 | Vue RouterVue.js 的官方路由https://router.vuejs.…

Java/Python/Go不同开发语言基础数据结构和相关操作总结-GC篇

Java/Python/Go不同开发语言基础数据结构和相关操作总结 1. 常见gc方式1.1 gc判断对象是否存活1.2 引用计数法1.2 标记-清除算法1.3 复制算法1.4 标记-压缩算法1.5 分代收集算法 2. java的gc方式以及垃圾回收器2.1 gc方式2.1 gc回收器2.1.1 Serial收集器2.1.2 ParNew收集器2.1.…

SSM---Mybatis查询数据库的功能

Mybatis查询数据库的功能流程&#xff1a; 在maven中加入mybatis依赖&#xff0c;mysql驱动依赖创建一张student表创建表对应的实体类&#xff1a;student类&#xff0c;用来保存表中的每行数据创建持久层的DAO接口&#xff0c;用来定义操作数据库的方法创建这个表对应的sql映…

计算机设计大赛 深度学习图像风格迁移 - opencv python

文章目录 0 前言1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习图像风格迁移 - opencv python 该项目较为新颖&#xff0c;适合作为竞赛课题…

IDEA下新建SpringBoot项目详细步骤

在IDEA下使用Spring Initializer&#xff1a; 一、新建项目&#xff0c;利用阿里云网址https://start.aliyun.com/下载项目&#xff0c;来到Spring Initializer模块&#xff1a; 我的jdk是8&#xff0c;构建Maven类型的项目&#xff0c;Java版本选8&#xff0c;Group为公司名。…

二阶低通滤波器(博途PLC SCL源代码)

在学习滤波器之前我们先了解下截止频率的准确定义,周期正弦信号经过传递函数后的输出信号,其幅值衰减-3dB时对应的频率。-3dB的含义是幅值衰减为原来的约0.707。更多滤波器信号处理相关内容请参看下面文章链接: 1、PLC一阶低通滤波器 https://rxxw-control.blog.csdn.net/…

前端路由与后端路由的区别

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

JSONVUE

1.JSON学习 1.概念: JSON是把JS对象变成字符串. 2.作用: 多用于网络中数据传输. JavaScript对象 let person{name:"张三",age:18}//将JS对象转换为 JSON数据let person2JSON{"name":"张三","age":18}; 3.JS对象与JSON字符串转换…

读人工不智能:计算机如何误解世界笔记03_AlphaGo

1. 人工智能 1.1. “人工智能”这个词听起来就是电影里的意象 1.1.1. 电影《星际迷航&#xff1a;下一代》中栩栩如生的机器人“数据少校” 1.1.2. 电影《2001太空漫游》中的哈尔9000 1.1.3. 电影《她》中的人工智能系统萨曼莎 1.1.4. 漫威系列漫画和电影中钢铁侠的管家贾…

前端常用6种数据加密方式的使用(最详解)

目录 前言 一、6种常用加密方案 1.Base64加密 2.MD5加密&#xff08;不可逆&#xff09; 3.sha256加密 4.sha1加密&#xff08;相比于MD5 安全性高&#xff0c;但是 速度慢&#xff09; 5.AES加密 6.字符串的编码和解码 二、结语 往期回顾 前言 相信大家在工作或面试…