zoukankan      html  css  js  c++  java
  • 关于曲线 规划 算法 线性 S曲线 贝塞尔曲线

         工控领域经常会涉及速度加减速的算法:线性加减速,S曲线加减速(sin函数,拓展其他三角函数曲线), 贝塞尔曲线,等等。

     线性加减速:    设定起始速度V0,目标速度V1,加速时间Ta(s,或加速度),这个的任务执行周期为ΔT( ms 级 或者设定定时器,定时时间必须大于任务周期否则还是按任务周期计算输出)。

        int  iCounter ;

      iCounter = Ta/(ΔT/1000) ;     //计算达到输出  任务需执行的  周期数。

     for(int i =0; i<iCounter;i++ ) 

      Vout = V0+i*(V1-V0)/iCounter;          // Vout  为每个周期 输出 的 目标 速度。

    S曲线加减速: 设定起始速度V0,目标速度V1,加速时间Ta(s,或加速度),这个的任务执行周期为ΔT( ms 级 或者设定定时器,定时时间必须大于任务周期否则还是按任务周期计算输出)。

      int  iCounter ;

      iCounter = Ta/(ΔT/1000) ;     //计算达到输出  任务需执行的  周期数。

      for(int i =0; i<iCounter;i++ ) 

         Vout = V0+(V1-V0)(1+Sin( (pi/iCounter)*i-pi/2 ));          // Vout  为每个周期 输出 的 目标 速度。

    贝塞尔曲线:很少或者基本不用贝塞尔曲线来规划 曲线加减速,但是有必要了解贝塞尔曲线的原理,及其低阶曲线的算法(3、4控制点)。

    贝塞尔曲线原理:

    下面我们就通过例子来了解一下如何用 de Casteljau 算法绘制一条贝塞尔曲线。

    在平面内任选 3 个不共线的点,依次用线段连接。enter image description here

    在第一条线段上任选一个点 D。计算该点到线段起点的距离 AD,与该线段总长 AB 的比例。enter image description here

    根据上一步得到的比例,从第二条线段上找出对应的点 E,使得 AD:AB= BE:BCenter image description here

    连接这两点 DE。enter image description here

    从新的线段 DE 上再次找出相同比例的点 F,使得 DF:DE= AD:AB= BE:BCenter image description here

    到这里,我们就确定了贝塞尔曲线上的一个点 F。接下来,请稍微回想一下中学所学的极限知识,让选取的点 D 在第一条线段上从起点 A 移动到终点 B,找出所有的贝塞尔曲线上的点 F。所有的点找出来之后,我们也得到了这条贝塞尔曲线。enter image description here

    如果你实在想象不出这个过程,没关系,看动画!enter image description here

    回过头来看这条贝塞尔曲线,为了确定曲线上的一个点,需要进行两轮取点的操作,因此我们称得到的贝塞尔曲线为二次曲线(这样记忆很直观,但曲线的次数其实是由前面提到的伯恩斯坦多项式决定的)。

    当控制点个数为 4 时,情况是怎样的?enter image description here

    步骤都是相同的,只不过我们每确定一个贝塞尔曲线上的点,要进行三轮取点操作。如图,AE:AB= BF:BC= CG:CD= EH:EF= FI:FG= HJ:HI,其中点 J 就是最终得到的贝塞尔曲线上的一个点。enter image description here

    这样我们得到的是一条三次贝塞尔曲线。enter image description here

    看过了二次和三次曲线,更高次的贝塞尔曲线大家应该也知道要怎么画了吧。那么比二次曲线更简单的一次(线性)贝塞尔曲线存在吗?长什么样?根据前面的介绍,只要稍作思考,想必你也能猜出来了。哈!就是一条直线~enter image description here

    能画曲线也能画直线,是不是很厉害?要绘制更复杂的曲线,控制点的增加也仅仅是线性的。这一特点使其不光在工业设计领域大展拳脚,就连数学基础不好的人也可以比较容易地掌握,比如大多数平面美术设计师们。enter image description here

    上面介绍的内容并不足以展示贝塞尔曲线的真正威力。推广到三维空间的贝塞尔曲面,以及更进一步的非均匀有理 B 样条(NURBS),早已成为当今计算机辅助设计(CAD)的行业标准,不论是我们平常用到的各种产品,还是在电影院看到的精彩大片,都少不了它们的功劳。

     

    2. 思路解析

    百度百科上给出的一般参数公式是这样的: 给定点 P0,P1,P2, ... ,Pn,其贝塞尔曲线公式如下(即贝塞尔曲线上的点 B(t) 可由如下公式计算得到):

     
     
     
     
     
     
    这里写图片描述

    可以看出其公式是由一个格式固定的表达式之和来表示,这个表达式就是关键:

     
     

    该表达式可分为四个部分看:

    • 从 i 递增到 n 的常数部分
    • Pi 坐标部分
    • (1 - t)^(n - i)
    • t^i 可以看出这四部分都与 i 的值相关,此外 t 值的计算方式为:i/(n+1)
    如果直接从上面的公式上找规律比较抽象,那就从具体的例子中找规律吧:

    设 Bt 为要计算的贝塞尔曲线上的坐标,N 为控制点个数,P0,P1,P2..Pn 为贝塞尔曲线控制点的坐标,当 N 值不同时有如下计算公式: 如 N 为 3 表示贝塞尔曲线的控制点有 3 个点,这时 n 为 2 ,这三个点分别用 P0,P1,P2 表示。

    • N = 3: P = (1-t)^2P0 + 2(1-t)tP1 + t^2*P2
    • N = 4: P = (1-t)^3P0 + 3(1-t)^2tP1 + 3(1-t)t^2P2 + t^3*P3
    • N = 5: P = (1-t)^4P0 + 4(1-t)^3tP1 + 6(1-t)2*t2P2 + 4(1-t)t^3P3 + t^4*P4

    将贝塞尔曲线一般参数公式中的表达式用如下方式表示: 设有常数 a,b 和 c,则该表达式可统一表示为如下形式: a * (1 - t)^b * t^c * Pn;

    分析当 N 分别为3,4,5 时对应 a,b,c 的值: 如 N = 3 时,公式有三个表达式,第一个表达式为 (1-t)^2*P0,其对应 a,b,c 值分别为:1,2,0

    • N = 3:   1,2,0   2,1,1   1,0,2 a: 1 2 1 b: 2 1 0 c: 0 1 2
    • N = 4:   1,3,0   3,2,1   3,1,2   1,0,3 a: 1 3 3 1 b: 3 2 1 0 c: 0 1 2 3
    • N = 5:   1,4,0   4,3,1   6,2,2   4,1,3   1,0,4 a: 1 4 6 4 1 b: 4 3 2 1 0 c: 0 1 2 3 4

    根据上面的分析就可以总结出 a,b,c 对应的取值规则:

    • b: (N - 1) 递减到 0     (b 为 1-t 的幂)
    • c: 0 递增到 (N - 1)     (c 为 t 的幂)
    • a: 在 N 分别为 1,2,3,4,5 时将其值用如下形式表示:
      N=1:---------1 N=2:--------1  1 N=3:------1  2  1 N=4:-----1  3  3  1 N=5:---1  4  6  4  1 a 值的改变规则为: 杨辉三角

    接下来就实现它:先再来一个例子
    比如计算控制点坐标分别为:P0(3,8),P1(2,3),P2(2,7),想要返回 10 个在贝塞尔曲线上的点,用 java 可以这样写:

    float[] p0 = {3, 8};        
    float[] p1 = {4, 3};        
    float[] p2 = {2, 7};        
    float[][] result = new float[10][2];        
    for (int i = 0; i < 10; i++)
    {            
    float t = i / 10;           
    result[i][0] = (float) (1 * Math.pow(1 - t, 2) * Math.pow(t, 0) * p0[0] + 2 * Math.pow(1 - t, 1) * Math.pow(t, 1) * p1[0] + 1 * Math.pow(1 - t, 0) * Math.pow(t, 2) * p2[0]);           
    result[i][1] = (float) (1 * Math.pow(1 - t, 2) * Math.pow(t, 0) * p0[1] + 2 * Math.pow(1 - t, 1) * Math.pow(t, 1) * p1[1] + 1 * Math.pow(1 - t, 0) * Math.pow(t, 2) * p2[1]);     
    }
  • 相关阅读:
    准备 FRM 考试——方法、工具与教训
    930. 和相同的二元子数组 前缀和
    1906. 查询差绝对值的最小值 前缀和
    剑指 Offer 37. 序列化二叉树 二叉树 字符串
    815. 公交路线 BFS
    518. 零钱兑换 II dp 完全背包
    1049. 最后一块石头的重量 II dp
    5779. 装包裹的最小浪费空间 二分
    5778. 使二进制字符串字符交替的最少反转次数 字符串 滑动窗口
    474. 一和零 dp
  • 原文地址:https://www.cnblogs.com/oneway1990/p/9820884.html
Copyright © 2011-2022 走看看