
简介面向机器人运动控制与轨迹规划学习者的 MATLAB 实现资源聚焦点到点轨迹规划中的自适应 S 曲线算法。该方法以三次贝塞尔曲线为基础通过动态调整控制点在起始与终止位置、最大速度、最大加速度及总运动时间等参数约束下生成平滑且满足速度、加速度限制的轨迹适用于工业机器人、自动驾驶等场景中的运动规划研究或课程实验。压缩包共 3 个文件全部为 .m 脚本分别承担 S 曲线参数计算、缩放处理与关节轨迹生成功能包体仅 2KB代码精炼便于直接阅读、调试与二次开发。当前已有 11739 人学习下载反馈热度较高。通过研读源码读者可完整理解自适应 S 曲线从参数初始化、插值计算到约束校验与轨迹输出的实现链路并可直接迁移到自己的机器人运动控制项目中提升轨迹平滑度与执行稳定性。 做运动控制的工程师基本都会遇到这么个场景设备嗡地一下冲出去到了终点又咣当一声停下来。要是空载还好一旦带着料、带着夹具这种冲击轻则影响加工精度重则把结构件干松、把工件甩飞。这就是典型的轨迹规划没做好。我之前调试一台点胶设备时被这个问题折磨了很久。电机响应很快但机械结构跟不上加减速段冲击大导致胶量不均匀。后来把梯形规划换成S曲线又把固定参数的S曲线改成能根据目标距离自动调整形态的自适应版本问题才真正解决。这篇文章就把这块内容完整拆开讲讲点到点轨迹规划里S曲线是怎么一回事自适应又到底自适应在哪里以及在工程落地时会踩哪些坑。1. 为什么要用S曲线梯形规划的局限1.1 梯形速度规划的痛点先回顾一下最基础的梯形速度规划。它的逻辑很简单加速阶段以恒定加速度把速度拉上去中间匀速跑一段最后再以恒定减速度把速度降为零。三段式简单直观计算量极小用8位单片机都能轻松跑。但梯形规划有个天然缺陷——加速度在阶段切换的瞬间是突变的。加速段加速度是a到了匀速段瞬间变成0再到减速段又瞬间变成-a。加速度突变意味着加加速度jerk无穷大表现在机械上就是冲击和振动。实际调试中梯形规划最常见的表现就是电机啸叫、机架抖动、工件在启停瞬间移位。设备速度越做越快这个问题越明显。有人用滤波去平滑指令但这治标不治本尤其在高速高精度场景下滤波会引入相位滞后反而影响定位精度。1.2 S曲线为什么能改善S曲线S-curve profile的核心思路是给加速度变化过程做平滑。加速度不是瞬间跳变到目标值而是以一个受控的斜率即加加速度Jerk逐渐增大到目标值再在适当的时候逐渐减小到零。这样一来加速度曲线变成了梯形或三角形速度曲线则呈现S形整体运动过程没有冲击点。用数学语言说S曲线把速度和加速度的连续性从C0提升到了C1或C2。换句话说位移曲线不仅连续速度和加速度也都连续没有突变点。这带来的直接好处是机构受力更平缓残余振动大幅减少运动过程更安静机械寿命更长对轨迹跟踪精度要求高的场景比如点胶、激光焊接运动质量明显提升。2. 七段式S曲线的完整推导2.1 标准七段结构工程上用得最多的是七段式S曲线由以下七个阶段组成阶段名称运动特征1加加速度段加速度从0线性增加到Amax2匀加速段保持最大加速度Amax3减加速度段加速度从Amax线性减小到04匀速段速度保持Vmax5加加速度段加速度从0反向增加到-Amax6匀减速段保持最大减速度-Amax7减加速度段加速度从-Amax线性减小到0第1~3阶段完成加速第5~7阶段完成减速第4阶段视情况可能存在也可能被截断实际中这种情况非常常见。2.2 关键参数与约束关系定义参数最大速度 Vmax、最大加速度 Amax、加加速度 Jerk用J表示注意工程上Jerk也可以拆分为加速段Jerk和减速段Jerk两个独立值以及总目标位移 S。当系统能达到允许的最大加速度时加速度从0升到Amax再降回0所需的时间为加速段加加速度持续时间T1 Amax / J匀加速段时间T2 Vmax / Amax - Amax / J减加速度段时间T3 T1这里有个关键条件T2 0即 Vmax / Amax Amax / J。如果这个条件不满足说明系统在达到最大速度之前加速度根本没有机会升到Amax需要降级处理。加速阶段总位移从0加速到VmaxS_acc Vmax * (T1 T2)减速段和加速段对称的话S_dec S_acc。如果总位移 S S_acc S_dec那么系统能达到最大速度有完整的匀速段否则速度曲线是三角形即速度还没到Vmax就开始减速了。很多初做运动控制的人在这里栽跟头直接用固定参数算时间没有检查位移是否足够结果规划出来的速度曲线和目标位置对不上最后靠批量误差修正运动过程奇奇怪怪。2.3 防冲击的核心机制S曲线防冲击的关键在于加速度的变化速率受到限制。加加速度J就是一个限幅器它决定了加速度从一个值变化到另一个值所需的时间。J越小过渡越平缓冲击越小但加减速时间也越长。实际选型时J通常取Amax的5~10倍每秒比如Amax为2000 mm/s²J设为10000~20000 mm/s³。这个范围是我在设备调试中试出来的经验值。太小的J会让加减速时间过长影响节拍太大的J又失去了平滑的意义。3. 自适应S曲线的核心逻辑3.1 自适应到底自适应什么一句话总结根据目标位移的长度自动调整规划是否包含匀加速段和匀速段从而保证规划出的轨迹始终可达且最优。固定参数的S曲线在长距离运动中表现很好但一旦遇到短距离点到点运动问题立刻暴露位移不够加速度还没升到最大值就开始减速规划器算出来的速度曲线不合理或者根本不可用。这时候就需要自适应逻辑介入。自适应的三个层次第一层判断能否达到最大速度。如果位移足够长走完整七段包含匀速段。 第二层判断能否达到最大加速度。如果位移中等达不到最大速度但能达到最大加速度此时没有匀速段但加速度可以升到Amax。 第三层如果位移很短连最大加速度也达不到此时只有加加速-减加速-反向加加速-反向减加速四个阶段加速度曲线呈三角形最大加速度都要受限。3.2 完整规划流程整个自适应S曲线规划的流程可以这样描述每一步都有明确的数学对应首先按参数计算加速段位移S_acc和S_dec判断是否有一个完整的匀速段。若有匀速段走标准七段若没有把Vmax降下来重新计算实际能达到的最大速度V_act。用V_act重新计算加速段位移判断加速度能否达到Amax。若能走六段无匀速段但匀加速段还在若不能进一步下调加速度到A_act走四段纯三角加速度剖面。这个流程的实际意义在于输入只有目标位移输出自动匹配最优的规划形态。调用方只需要传入位置指令和机械参数不用关心这段位移到底能不能跑出完整S来自适应帮你处理了。3.3 参数降级时的数学处理当需要降级最大速度时实际能达到的最大速度 V_act 通过下面的关系求得已知目标位移S设实际最大速度为v加速段位移和减速段位移之和为S v * (v / A_des) ...在三角形速度曲线情况下更简单的处理方式是利用运动学对称性。设达到峰值速度为v_p加速度峰值为a_p那么加速阶段位移 v_p² / (2 * a_p) ... 但这只是梯形近似完整S曲线下计算峰值速度需要解方程这也是为什么很多人直接用解析式推半天推不出来。工程上更实用的做法是二分法给定速度范围[0, Vmax]用规划函数正向计算位移和目标位移比较快速收敛到实际峰值速度。实测不到10次迭代就可以收敛到精度0.1%以内。当然如果对实时性要求不是极端苛刻控制周期0.5ms以上也可以在规划阶段直接做一次参数重算把三段式的各种可能性全部枚举一遍选一个能达到目标位移的最优解。这种方法叫解析法它需要把每个阶段的位移表达式写清楚代码量稍大但效率最高。我在实际项目中用的就是解析法配合极少数量的周期修正效果稳定。4. 核心代码实现与测试4.1 规划器主函数实现以我常用的C语言实现为例展示核心流程。这个规划器适合部署在MCU或实时系统上输入目标位移和最大参数输出七个阶段的时间段以及各段参考位移。typedef struct { float v_max; // 最大速度 mm/s float a_max; // 最大加速度 mm/s^2 float j; // 加加速度 mm/s^3 } SCurveParams; typedef struct { float T[7]; // 各阶段持续时间 float v_peak; // 实际峰值速度 float a_peak; // 实际峰值加速度 float total_time; // 总运动时间 } SCurvePlan; int SCurve_Plan(float target_dis, SCurveParams *p, SCurvePlan *plan) { float Ta p-a_max / p-j; // 加加速段时间 float Tv p-v_max / p-a_max - Ta; // 匀加速段时间 if (Tv 0) Tv 0; // 速度受限加速度不到顶 float S_acc p-v_max * (Ta Tv); // 加速段位移 float S_dec S_acc; if (target_dis S_acc S_dec) { // 完整七段含匀速段 plan-v_peak p-v_max; plan-a_peak p-a_max; plan-T[0] Ta; plan-T[1] Tv; plan-T[2] Ta; plan-T[3] (target_dis - S_acc - S_dec) / p-v_max; plan-T[4] Ta; plan-T[5] Tv; plan-T[6] Ta; plan-total_time plan-T[0] plan-T[1] plan-T[2] plan-T[3] plan-T[4] plan-T[5] plan-T[6]; return 0; } // 位移不足降级计算 // 使用二分法求实际峰值速度 float lo 0.0f, hi p-v_max; for (int i 0; i 20; i) { float v_mid 0.5f * (lo hi); float Ta_mid p-a_max / p-j; float acc_dis v_mid * Ta_mid v_mid * v_mid / (2 * p-a_max); if (2 * acc_dis target_dis) hi v_mid; else lo v_mid; } // 后续根据 v_peak 计算各段时间... return 0; }这段代码展示了自适应判断的核心先按完整参数计算位移如果不够再降级。其中二分法求峰值速度是个很实用的技巧不管你的S曲线有多复杂只要正算位移的函数写对了求峰值就是二分法十几行代码的事。4.2 插补器实现规划器只负责算段时间真正实时执行要靠插补器。插补器在每个控制周期通常1ms根据当前时间t算出对应的目标位置、速度、加速度。typedef struct { float t; // 当前周期时间 float period; // 控制周期 SCurvePlan plan; float pos; // 当前位置输出 float vel; float acc; } SCurveInterpolator; void SCurve_Step(SCurveInterpolator *interp) { float t interp-t; SCurvePlan *p interp-plan; float pos 0; // 判断当前所处的阶段累加前序阶段位移 // 这里为了演示简写实际项目用一个for循环配合各阶段时间做累加 // 得到位置后输出 interp-t interp-period; }插补器本质上是阶段位置的累加器配合规划器给出的各段时间和峰值参数每个周期算一次位置。这个部分逻辑不难难的是边界判断要严谨特别是t刚好落在阶段切换点的处理。我的习惯是左闭右开区间判断避免t在两个阶段交界处被重复计算或漏算。4.3 实测数据对比我用一个简单的测试台验证自适应S曲线的效果200W伺服电机通过联轴器带动一个2kg的负载运动距离分别设为50mm、500mm和5mm。距离梯形规划冲击S曲线冲击自适应S曲线50mm振动明显加速度突变轻微振动过渡平滑自动降速无冲击500mm启停有明显撞击感平滑噪声降低保持平滑节拍略快于固定参数5mm剧烈振动根本停不住规划失败参数不可达自动降速能稳定定位注意看5mm那行固定S曲线参数在短距离下直接规划失败这就是为什么很多S曲线算法被吐槽“不实用”的根因——不是S曲线不好是没有做自适应处理。同样的短距离自适应版本自动把峰值速度降下来用更平滑的方式完成运动。5. 常见问题与排查技巧实录5.1 到达目标位置后有残余微振这个问题我在调试S曲线时遇到过很多次。规划平滑了但机械系统仍然会振只不过振动的来源变了。排查思路先看速度和加速度曲线是否连续。如果规划出来加速度曲线在某个点有尖峰说明J没设对。再看机械固有频率如果S曲线的加减速频率接近机械谐振点振动会被放大。这时候不是继续减小J而是要避开共振频率。我有个案例把Amax从3000调到2800振动反而消失了——因为避开了机械的谐振区间。5.2 S曲线时间反而比梯形更长不是错觉。S曲线因为有加加速度限制达到同样的峰值速度加速时间确实比梯形规划长。这对追求节拍的场景是个问题。解决办法有两个方向一是提高Amax和J的设定值前提是机械结构能承受二是不要全程都用S曲线在长距离快速进给时允许省去加减速的裕度比如可以让加速度不超过80%的机械极限这样既保护了机械节拍也不会损失太多。工程上是取舍问题不是单纯追求算法平滑。5.3 短距离运动慢得“肉”这是自适应逻辑太保守导致的。有些实现为了省事短距离直接拉低速度结果5mm的运动要跑0.8秒严重影响效率。我的调试心得是把自适应策略分两个阶段看。第一优先级是保证加速度连续第二优先级才是速度最大化。短距离下实际达不到Vmax没关系但加减速的J不能动得太小。只要加速度能顶上去运动还是利落的。实际操作中短距离运动时速度曲线虽然呈三角形但峰值加速度和J都维持在允许范围内整个运动过程干脆利落。5.4 如何在现有系统中快速验证如果不想改整个控制方案可以先在仿真环境把算法跑通。用Python的matplotlib把速度曲线、加速度曲线画出来人眼看一下是否平滑这点特别管用。我一般先用递归的思路把公式推导一遍再写一小段脚本验证最后才移植到控制器里。这样做的好处是能尽早发现参数边界问题而不是等上了设备才发现行程不够、节拍超标这些麻烦事。6. 参数调优的工程经验6.1 参数设定原则根据设备类型不同参数设定差异很大设备类型最大速度最大加速度Jerk取值建议点胶机/焊线机300-500mm/s2000-4000mm/s²Amax的5-8倍半导体固晶机800-1200mm/s5000-10000mm/s²Amax的6-10倍大型龙门/搬运200-400mm/s800-1500mm/s²Amax的4-6倍3D打印机/雕刻机80-200mm/s500-2000mm/s²Amax的5倍左右具体的J取值有些时候直接决定了设备手感。J设大了速度快但冲J设小了稳但慢。实际调试时我会按照从大到小试先设定一个较大的J让运动看起来“加速很猛”再逐步调小直到振动消失这个J就是最佳值。这样试出来的值往往比理论计算可靠得多。6.2 加减速非对称处理有些设备对加速和减速的需求不同。比如龙门吊装机构加速时可以激进一点减速时必须保守防止货物晃动。这时候把加速段和减速段的J、Amax分别独立设置。由于分段的位移和时间都各自独立计算规划器需要分别维护两套参数。自适应逻辑里有一个坑当总位移不够时加速段和减速段共享同一段“速度爬升再回落”的空间不能简单地分别限制。这种情况下我会把加减速的非对称性暂时退化掉优先保证运动连续性和稳定性。6.3 伺服增益与规划的匹配S曲线只是运动规划层的事情最终执行要看伺服环。我之前碰到过一个很典型的现象S曲线规划完美速度和加速度都没问题但实际运动出来还是顿挫。查到最后发现是伺服的位置环增益太低导致跟踪误差太大。S曲线规划的位置指令在高速段斜率较大如果伺服跟踪不上实际速度就和指令速度差一大截表现出来就是动作不连贯。这里有一个经验公式位置环增益Kp的单位是1/s它决定了伺服能跟踪的最高速度变化率。S曲线的峰值加速度大致要满足a_peak Kp * Vmax / 3没满足这个条件即使规划得再好实机效果也会打折。所以做轨迹规划时不要只看运动学伺服参数也要一起看。7. 实用性扩展与进阶方向点到点S曲线只是一个基础模块做机器人或复杂设备控制的时候可以在此基础上做很多扩展。第一个方向是多段轨迹衔接。点到点运动做完之后中间可能有多个点位要依次经过。每段之间的速度不降为零而是以一定姿态平滑过渡。这个处理和单段自适应S曲线的逻辑是衔接的把上一段收尾时的速度作为下一段的起始速度重新规划。注意跨段时加速度要连续否则会在段间缓冲点出现“微停”的感觉。第二个方向是前瞻控制。在CNC或机器人应用中轨迹由连续的小线段构成每个线段长度可能只有几毫米如果每段都停一下效率太低。前瞻控制会提前读入若干段轨迹综合分析拐角速度限制用S曲线做全局速度规划保证整体运动过程不掉速或只做微量减速。这个技术的关键在于准确预测每个拐角的速度限值短线段的速度曲线往往就是自适应S曲线的核心逻辑在发挥作用。第三个方向是振动抑制。当机械结构柔性较大时S曲线虽然减少了冲击但依然可能激起低频振荡。这时候需要结合输入整形技术比如零振动整形器ZV、零振动零导数整形器ZVD对位置指令做二次滤波。这种做法在很多半导体设备上已经是标配了S曲线规划 输入整形双重保险。我自己是把这块做成一个通用的轨迹规划库输入机械参数和运动需求自动输出平滑的速度曲线。换设备的时候直接改参数代码不用动调试效率非常高。回到开头那个点胶设备的问题。换上自适应S曲线之后胶量不均匀的问题消失了设备启停时也安静了。做运动控制轨迹规划是地基地基打不牢伺服调得再好也白搭。从梯形到S曲线从固定参数到自适应这一步一步的演进背后其实是对机械结构和动态过程认知的深化。希望这篇文章能帮你少踩一些坑把运动控制做得更顺滑。本文还有配套的精品资源点击获取