S曲线控制

 关于运动控制中S型速度曲线的简单演示(C++实现)_速度曲线算位置曲线-CSDN博客

步进电机有很多种算法,主要集中在速度的控制,其中S比较常见。上边是其他作者的作品, 这里截取一段代码 作为记录。

#include <stdio.h>
#include <math.h>

#define  FP64 double


int main(void)
{
    /****************************  定义相关变量(需要映射到PLC寄存器才能进行监控)   ***********************/
    FP64 v_start;   //初速度
    FP64 v_end;     //末速度
    FP64 v_max = 0;     //最大速度(有匀速段时,v_max = v_target)
    
    /*根据需要修改*/
    v_start = 100;
    v_end = 150;

    FP64 s_target;   //目标位移量
    FP64 v_target;   //目标速度
    FP64 a_target;   //目标加速度
    FP64 d_target;   //目标减速度
    FP64 j_max;      //目标加加速度
    FP64 t_sum;
    FP64 L;          //算出的位移量
    FP64 v_real;     //实际的最大速度


    FP64 s_max;      //L>s_target时候规划的位移

    /*可以根据需要修改*/
    j_max = 2000;       //目标加加速度
    a_target = 2000;    //目标加速度
    d_target = 3000;    //目标减速度
    v_target = 5000;    //目标速度
    s_target = 3000;    //目标位移

    int  t;         //运行时间
    FP64 t_aver;    //匀速区时间
    FP64 t1;        //加加速时间
    FP64 t2;        //匀加速时间
    FP64 t3;        //减加速时间
    FP64 t4;        //匀速运行时间
    FP64 t5;
    FP64 t6;
    FP64 t7;


    FP64 v1;
    FP64 v2;
    FP64 v3;
    FP64 v4;
    FP64 v5;
    FP64 v6;
    FP64 v7;

    FP64 a_max;     //加速度最大值(拥有匀加速段时 a_max = a_target)
    FP64 d_max;

    FP64 s1;        //加加速位移 s1
    FP64 s2;        //匀加速位移 s2
    FP64 s3;        //减加速位移 s3
    FP64 s4;        //匀速位移   s4
    FP64 s5;        //加减速位移 s5
    FP64 s6;        //匀减速位移 s6
    FP64 s7;        //减减速位移 s7

    FP64 s_acc;     //加速区位移
    FP64 s_dec;     //减速区位移

    FP64 j_cur;     //当前加加速度
    FP64 a_cur;     //当前加速度
    FP64 v_cur;     //当前速度
    FP64 s_cur;     //当前位移量
    FP64 v_down;

    FP64 v_low;
    FP64 v_high;

    short int   end_count=0;
    short int   flag = 0;
    short int   flag1 = 0;
    short int   count=0;

        for (t = 0; t < 10000000000; t++)
        {
            if (v_max == 0)         //只有第一遍
            {
                /***********************************根据目标速度,加速度,加加速度等规划出加速区和减速区******************/
                if ((v_target - v_start) > a_target * a_target / j_max) //匀加速段
                {
                    a_max = a_target;

                    t1 = a_max / j_max;
                    v1 = v_start + 0.5 * j_max * t1 * t1;
                    s1 = v_start * t1 + (j_max * t1 * t1 * t1) / 6;

                    t2 = (v_target - v_start) / a_max - t1;
                    v2 = v1 + a_target * t2;
                    s2 = v1 * t2 + 0.5 * a_max * t2 * t2;

                    t3 = t1;
                    v3 = v2 + a_max * t3 - 0.5 * j_max * t3 * t3;
                    s3 = v2 * t3 + j_max * t3 * t3 * t3 / 3;
                }
                else
                {
                    a_max = sqrt((v_target - v_start) * j_max);
                    t1 = sqrt((v_target - v_start) / j_max);
                    s1 = v_start * t1 + (j_max * t1 * t1 * t1) / 6;
                    v1 = v_start + 0.5 * j_max * t1 * t1;
                    t2 = 0;
                    v2 = v1;
                    s2 = 0;
                    t3 = t1;
                    s3 = v2 * t3 + j_max * t3 * t3 * t3 / 3;
                    v3 = v2 + a_max * t3 - 0.5 * j_max * t3 * t3;
                }
                if (v_target - v_end > (d_target * d_target) / j_max)
                {
                    d_max = d_target;

                    t7 = d_max / j_max;
                    s7 = v_end * t7 + (j_max * t7 * t7 * t7) / 6;
                    v6 = v_end + 0.5 * j_max * t7 * t7;
                    t6 = (v_target - v_end) / d_max - t7;
                    s6 = v6 * t6 + 0.5 * d_max * t6 * t6;
                    v5 = v6 + d_target * t6;
                    t5 = t7;
                    s5 = v5 * t5 + j_max * t5 * t5 * t5 / 3;
                }
                else
                {
                    d_max = sqrt((v_target - v_end) * j_max);
                    t7 = sqrt((v_target - v_end) / j_max);
                    s7 = v_end * t7 + (j_max * t7 * t7 * t7) / 6;
                    v6 = v_end + 0.5 * j_max * t7 * t7;
                    t6 = 0;
                    s6 = 0;
                    t5 = t7;
                    v5 = v6;
                    s5 = v3 * t5 - j_max * t5 * t5 * t5 / 6;
                }

                L = 0.5 * ((v_start + v_target) * (t1 + t2 + t3) + (v_end + v_target) * (t5 + t6 + t7));

            }
                
            if (L >= s_target && v_max == 0)      //如果 L >= s_target,那么达不到目标速度,需要规划出实际最大速度,只有第一遍循环会进这个程序
            {
                t4 = 0;
                s4 = 0;
                v4 = v3;

                v_high = v_target;

                /*初速度较大*/
                if (v_start > v_end)
                {
                    v_low = v_start;
                }
                /*末速度较大*/
                else if (v_end > v_start)
                {
                    v_low = v_end;
                    end_count += 1;
                }

                v_max = 0.5 * (v_low + v_high);
            }
            /*如果 L < s_target 那么可以正常进行规划(有匀速段),标志位flag1=1*/
            else if (L < s_target)
            {
                v_max = v_target;
                flag1 = 1;
            }


            /***********************************  根据二分处理后的速度再算位移  ******************/
            if ((v_max - v_start) > a_target * a_target / j_max) //匀加速段
            {
                a_max = a_target;

                t1 = a_max / j_max;
                v1 = v_start + 0.5 * j_max * t1 * t1;
                s1 = v_start * t1 + (j_max * t1 * t1 * t1) / 6;

                t2 = (v_max - v_start) / a_max - t1;
                v2 = v1 + a_target * t2;
                s2 = v1 * t2 + 0.5 * a_max * t2 * t2;

                t3 = t1;
                v3 = v2 + a_max * t3 - 0.5 * j_max * t3 * t3;
                s3 = v2 * t3 + j_max * t3 * t3 * t3 / 3;
            }
            else
            {
                a_max = sqrt((v_max - v_start) * j_max);
                t1 = sqrt((v_max - v_start) / j_max);
                s1 = v_start * t1 + (j_max * t1 * t1 * t1) / 6;
                v1 = v_start + 0.5 * j_max * t1 * t1;
                t2 = 0;
                v2 = v1;
                s2 = 0;
                t3 = t1;
                s3 = v2 * t3 + j_max * t3 * t3 * t3 / 3;
                v3 = v2 + a_max * t3 - 0.5 * j_max * t3 * t3;
            }
            if (v_max - v_end > (d_target * d_target) / j_max)  //匀减速段
            {
                d_max = d_target;

                t7 = d_max / j_max;
                s7 = v_end * t7 + (j_max * t7 * t7 * t7) / 6;
                v6 = v_end + 0.5 * j_max * t7 * t7;
                t6 = (v_max - v_end) / d_max - t7;
                s6 = v6 * t6 + 0.5 * d_max * t6 * t6;
                v5 = v6 + d_target * t6;
                t5 = t7;
                s5 = v5 * t5 + j_max * t5 * t5 * t5 / 3;
            }
            else
            {
                d_max = sqrt((v_max - v_end) * j_max);
                t7 = sqrt((v_max - v_end) / j_max);
                s7 = v_end * t7 + (j_max * t7 * t7 * t7) / 6;
                v6 = v_end + 0.5 * j_max * t7 * t7;
                t6 = 0;
                s6 = 0;
                t5 = t7;
                v5 = v6;
                s5 = v3 * t5 - j_max * t5 * t5 * t5 / 6;
            }

            s_max = s1 + s2 + s3 + s5 + s6 + s7;        //s_max是二分后的位移

            /*二分后的位移无限接近目标位移,则标志位flag=1,开始规划*/
            if (s_max - s_target < 0.001 && s_max - s_target > 0)
            {
                flag = 1;
            }
            /*否则继续二分*/
            else
            {
                //二分法思想:改变上下限
                if (s_max < s_target)                   //如果规划出来的位移偏小
                {
                    v_low = v_max;
                }
                else {                                  //如果规划出来的位移偏大
                    v_high = v_max;
                }
                v_max = 0.5 * (v_low + v_high);
            }



            /***********************************  只有在标志位置位时才规划(画图)  ******************/
            if (flag == 1 || flag1 == 1)
            {
                if (flag1 == 1 )
                {
                    /*正常进行规划*/
                    t4 = (s_target - L) / v_max;
                    v4 = v3;
                    s4 = v4 * t4;
                }
                else if (flag == 1)
                {
                    t4 = 0;
                    v4 = v3;
                    s4 = 0;
                }


                t_sum = t1 + t2 + t3 + t4 + t5 + t6 + t7;

                if (t >= 0 && t < t1)
                {
                    j_cur = j_max;
                    a_cur = j_cur * t;
                    v_cur = v_start + 0.5 * j_cur * t * t;
                    s_cur = v_start * t + j_cur * t * t * t / 6;
                }
                else if (t >= t1 && t < t1 + t2 && t2 != 0)
                {
                    j_cur = 0;
                    a_cur = a_max;
                    v_cur = v1 + a_cur * (t - t1);
                    s_cur = s1 + v1 * (t - t1) + 0.5 * a_cur * (t - t1) * (t - t1);


                }
                else if (t >= t1 + t2 && t < t1 + t2 + t3)
                {
                    j_cur = -j_max;
                    a_cur = a_max - j_max * (t - t1 - t2);
                    v_cur = v2 + a_max * (t - t1 - t2) - 0.5 * j_max * (t - t1 - t2) * (t - t1 - t2);
                    s_cur = s1 + s2 + v2 * (t - t1 - t2) + 0.5 * a_max * (t - t1 - t2) * (t - t1 - t2) - j_max * (t - t1 - t2) * (t - t1 - t2) * (t - t1 - t2) / 6;


                }
                else if (t >= t1 + t2 + t3 && t < t1 + t2 + t3 + t4 && t4 != 0)
                {
                    j_cur = 0;
                    a_cur = 0;
                    v_cur = v3;
                    s_cur = s1 + s2 + s3 + v3 * (t - t1 - t2 - t3);

                }
                else if (t >= t1 + t2 + t3 + t4 && t < t1 + t2 + t3 + t4 + t5)
                {
                    j_cur = -j_max;
                    a_cur = -j_max * (t - t1 - t2 - t3 - t4);
                    v_cur = v4 - 0.5 * j_max * (t - t1 - t2 - t3 - t4) * (t - t1 - t2 - t3 - t4);
                    s_cur = s1 + s2 + s3 + s4 + v4 * (t - t1 - t2 - t3 - t4) - j_max * (t - t1 - t2 - t3 - t4) * (t - t1 - t2 - t3 - t4) * (t - t1 - t2 - t3 - t4) / 6;


                }
                else if (t >= t1 + t2 + t3 + t4 + t5 && t < t1 + t2 + t3 + t4 + t5 + t6 && t6 != 0)
                {
                    j_cur = 0;
                    a_cur = -d_max;
                    v_cur = v5 - d_target * (t - t1 - t2 - t3 - t4 - t5);
                    s_cur = s1 + s2 + s3 + s4 + s5 + v5 * (t - t1 - t2 - t3 - t4 - t5) - 0.5 * d_target * (t - t1 - t2 - t3 - t4 - t5) * (t - t1 - t2 - t3 - t4 - t5);

                }
                else if (t >= t1 + t2 + t3 + t4 + t5 + t6 && t < t1 + t2 + t3 + t4 + t5 + t6 + t7)
                {
                    j_cur = j_max;
                    a_cur = -d_max + j_max * (t - t1 - t2 - t3 - t4 - t5 - t6);
                    v_cur = v6 - d_max * (t - t1 - t2 - t3 - t4 - t5 - t6) + 0.5 * j_max * (t - t1 - t2 - t3 - t4 - t5 - t6) * (t - t1 - t2 - t3 - t4 - t5 - t6);
                    s_cur = s1 + s2 + s3 + s4 + s5 + s6 + v6 * (t - t1 - t2 - t3 - t4 - t5 - t6) - 0.5 * d_max * (t - t1 - t2 - t3 - t4 - t5 - t6) * (t - t1 - t2 - t3 - t4 - t5 - t6) + j_max * (t - t1 - t2 - t3 - t4 - t5 - t6) * (t - t1 - t2 - t3 - t4 - t5 - t6) * (t - t1 - t2 - t3 - t4 - t5 - t6) / 6;

                }
                else if (t > t1 + t2 + t3 + t4 + t5 + t6 + t7)
                {
                    a_cur = 0;
                    j_cur = 0;
                    v_cur = v_end;
                    return;
                }
            }
        }

        
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值