拓冰建站拓冰建站
首页 / 资讯中心 / 正文

S 曲线加减速算法完整详解(C# 原生实现,无第三方库)

基本概念基础物理定义s位移单位为 m/pulse脉冲表示物体位置的变化量。在伺服系统中通常以脉冲数计量例如1000 pulse 对应 0.1m 位移。v速度单位为 m/s定义为位移对时间的一阶导数描述位置变化的快慢程度。a加速度单位为 m/s²定义为速度对时间的一阶导数描述速度变化的快慢程度。J加加速度/Jerk单位为 m/s³定义为加速度对时间的一阶导数描述加速度变化的剧烈程度。在精密运动控制中限制 Jerk 可有效减少机械振动。运动控制模式梯形加减速加速度曲线呈梯形存在突变点如从 0 直接跳变到最大加速度导致 Jerk 理论值为无穷大。适用于对运动平稳性要求不高的场合但会在机械系统中产生冲击。S 曲线加减速通过限制最大 Jerk 值使加速度连续变化速度曲线呈现平滑的 S 形。典型应用于 CNC 机床、工业机器人等需要平稳启停的场景。七个标准运动阶段完整的 S 曲线运动过程可分解为 7 个阶段实际应用会根据移动距离和参数设置动态裁剪某些阶段加加速段加速度从 0 线性增长至斜率由决定。示例0.1s 内加速度从 0 增至 2m/s²J 20m/s³。匀加速段加速度保持恒定速度线性增长。示例保持 2m/s² 加速度持续 0.5s。减加速段加速度从线性减小至 0速度增长速率降低。示例0.1s 内加速度从 2m/s² 减至 0。匀速段保持恒定速度运动位移与时间呈线性关系。短距离运动中可能跳过此阶段。示例以 1m/s 匀速运动 2s。加减速段加速度从 0 负向增长至速度开始下降。示例0.1s 内加速度从 0 变为 -2m/s²。匀减速段保持负向最大加速度速度线性下降。示例保持 -2m/s² 加速度持续 0.5s。减减速段负加速度回归至 0速度平滑下降至 0。示例0.1s 内加速度从 -2m/s² 回归到 0。关键约束条件算法输入系统需提供以下参数总位移单位 m运动总距离如加工行程 0.5m。最大速度单位 m/s运动过程的速度上限如设定 1m/s。最大加速度单位 m/s²加速度绝对值上限如设定 2m/s²。最大加加速度单位 m/s³加加速度绝对值上限决定运动平滑性如设定 50m/s³。约束说明所有参数为绝对值算法自动处理方向正/反向位移。参数需满足物理约束关系例如 ( V_{max} \leq \sqrt{A_{max} \times S_{total}} )。短位移时算法可能跳过匀速段或匀加速/减速段。历史背景梯形速度曲线T-curve的局限性在早期数控设备和步进电机控制中梯形速度曲线T-curve凭借计算简单、易于实现的优势得到广泛应用。其运动过程由匀加速、匀速和匀减速三个阶段组成但存在显著缺陷在启动、加速切换和减速切换等关键时间点加速度会发生瞬时突变即加加速度Jerk为无穷大。这种突变引发以下问题机械振动与共振高速运行时加速度的阶跃变化易激发机械系统共振导致设备抖动降低加工精度。定位偏差加速度突变可能造成运动系统因惯性过冲或响应滞后使实际位置偏离目标位置。机械磨损频繁的冲击载荷会加速丝杆、导轨和轴承等关键部件的疲劳缩短使用寿命。S 曲线的发展与演进20 世纪 70 年代后欧美 CNC计算机数控控制器逐步引入平滑速度轮廓以优化运动控制性能。其中7 段 S 曲线包含加加速、匀加速、减加速、匀速、加减速、匀减速和减减速七个阶段因加速度连续变化的特性成为工业标准广泛应用于以下场景机器人高精度轨迹规划如焊接、装配等任务。高端数控机床减少切削振动提升加工表面质量。半导体搬运设备避免精密元件因振动受损。硬件算力的影响早期受限于 MCU微控制器和工控机的算力完整计算 7 段 S 曲线难以实时完成因此业界多采用简化版 5 段 S 曲线去除匀加速和匀减速段保留加加速、减加速、匀速、加减速和减减速。随着 DSP、FPGA 等高性能硬件的普及完整的 7 段 S 曲线得以大规模应用进一步提升了运动控制的平滑性和精度。国内厂商的技术应用目前汇川、埃斯顿、固高等国内主流运动控制厂商的运动控制卡及伺服系统其底层轨迹发生器均基于 7 段 S 曲线的优化算法并结合实际需求进行改进例如动态调整加加速度Jerk以适应不同负载自适应速度规划实现高速与高精度模式切换多轴同步插补确保复杂轨迹平滑性。这些技术的应用使国产运动控制系统在精度、稳定性和寿命方面逐步达到国际先进水平。核心原理分段运动方程时间域公式设定起始时刻 t0各阶段运动方程如下加加速段 (t∈[0,T₁])物体从静止开始运动加速度随时间线性增加加加速度J为常数其中J 为加加速度单位m/s³。匀加速段当加速度达到最大值时进入匀加速阶段持续时间其中边界值减加速段加速度线性减小至零对称减速过程其中边界值匀速段加减速段匀减速段减减速段后续阶段遵循相同规律通过递推公式计算各阶段边界条件。核心难点阶段时间预规划关键约束条件最大加加速度最大加速度最大速度目标位移计算流程计算理论加加速时间构建7段速度轮廓假设计算加速阶段可达峰值速度速度可行性判断若→ 存在匀速段7段完整否则→ 形成5段曲线无匀速段位移约束校验计算理论位移若→ 需重新规划降低峰值速度限制可能截断加速/减速阶段如变为3段曲线典型错误实现固定采用7段曲线未处理短行程场景未实现位移约束的递归校验逻辑忽略最大加速度可达性验证方向处理规范统一计算策略内部计算始终采用正向位移坐标系最终输出处理优势避免负速度/加速度的符号处理简化公式推导过程保证各阶段计算的数学一致性实现注意事项需在规划阶段预先确定运动方向所有限制参数取绝对值参与计算在运动过程中禁止动态改变方向运动轨迹规划执行流程详解整体架构系统采用两阶段分层设计结构轮廓预规划模块- 离线计算阶段完成运动曲线参数计算实时周期采样模块- 在线执行阶段按控制周期输出轨迹点详细执行流程初始化预规划一次性执行输入参数处理接收运动指令参数目标位移单位mm最大速度mm/s最大加速度mm/s²最大加加速度mm/s³处理位移量取绝对值保存为基准长度L记录原始位移符号作为运动方向sign1或-1基础参数计算计算基础加加速时间通过迭代算法求解各运动阶段持续时间T1加加速阶段T2匀加速阶段T3减加速阶段T4匀速阶段T5加减速阶段T6匀减速阶段T7减减速阶段轨迹参数计算计算各阶段分界时间点累计时间计算各阶段末端的累计位移量位置瞬时速度验证总位移是否达到目标值L若不满足则调整时间参数重新计算数据保存存储所有阶段的分界时间戳数组保存完整的七段S曲线参数集合实时周期运行每控制周期执行运行状态跟踪获取当前运动已运行时间从运动开始计时在预存时间戳数组中二分查找确定所属运动阶段轨迹点计算根据所处阶段选择对应的运动学方程加/减加速阶段三次多项式匀加/减速阶段二次多项式匀速阶段线性方程输出处理计算当前理论位置s、速度v、加速度a乘以方向系数sign得到实际指令值通过通信接口输出目标位置指令如脉冲指令或模拟量终止判断当≥ 总运动时间时标记运动完成清除运行状态标志位状态机设计状态迁移逻辑[Idle] │ ▼ (收到新运动指令) [Running] → 运动完成 → [Done] │ │ └── 错误发生 ──→ [Error]状态说明Idle(空闲)等待运动指令状态所有输出置零Running(运行中)轨迹生成状态每个控制周期计算新目标点Done(完成)运动正常结束状态保持最终位置Error(错误)异常状态需人工干预复位典型应用场景CNC机床轴控制工业机器人轨迹规划3D打印机运动控制自动化测试设备定位控制周期示例高性能场合100μs-1ms周期常规应用1-10ms周期低速设备10-100ms周期算法性能分析计算复杂度预规划阶段执行时机运动启动时仅执行一次初始化计算运算类型主要包括运动参数归一化处理、边界条件设定等基础算术运算复杂度分析固定次数的基本运算时间复杂度为O(1)示例加速度到加加速度的转换仅需1次除法和2次乘法运算周期执行阶段阶段判断每个控制周期执行1次运动状态机判断比较运算多项式求值每轴每周期计算3次多项式位置、速度、加速度复杂度分析固定次数的浮点运算时间复杂度保持O(1)对比优势相比数值积分方法如龙格-库塔法无误差累积效应采用纯解析解计算理论精度可达浮点数极限典型场景10秒运动时长下解析解位置误差1e-10m而4阶龙格-库塔法误差1e-5m误差特性核心优势基于三次多项式的解析解计算无数值积分截断误差无迭代计算误差传播主要误差源IEEE 754双精度浮点数机器精度约2.22e-16控制周期离散化的时间量化误差误差验证x86平台测试显示1ms控制周期下轨迹跟踪误差1nm实时性要求计算负载单周期运算量100 FLOP处理器对比处理器类型支持周期PC处理器i7100μsCortex-M7 MCU1ms稳定运行51单片机建议10ms控制周期推荐高动态场景1ms工业机械臂普通场景5ms3D打印机低功耗场景10ms仓储机器人资源占用内存特性无需预生成轨迹点数组传统方法需MB级缓存运行时仅存储当前运动参数约100字节/轴扩展优势支持超长行程运动如千米级直线电机内存占用与运动时间/距离无关典型应用天文望远镜跟踪连续运行数小时内存占用不变完整原生代码特性✅ 完整 7 段 S 曲线自动裁剪短行程自动退化为 5 段 / 3 段✅ 支持正向、反向运动✅ 状态机管理✅ 实时获取当前位置、速度、加速度✅ 使用 double 高精度浮点✅ 可直接接入定时器周期调用using System; /// summary /// 七段式S曲线加减速轨迹规划器 /// 纯原生C#无第三方依赖 /// /summary public class SCurveProfile { #region 输入运动参数 /// summary总目标位移可正负表示方向/summary public double TargetDistance { get; private set; } /// summary最大允许速度绝对值/summary public double VMax { get; private set; } /// summary最大允许加速度绝对值/summary public double AMax { get; private set; } /// summary最大加加速度Jerk绝对值/summary public double JMax { get; private set; } #endregion #region 阶段时间 T1~T7 public double T1 { get; private set; } //加加速时长 public double T2 { get; private set; } //匀加速时长 public double T3 { get; private set; } //减加速时长 public double T4 { get; private set; } //匀速时长 public double T5 { get; private set; } //加减速时长 public double T6 { get; private set; } //匀减速时长 public double T7 { get; private set; } //减减速时长 /// summary整条运动总时间/summary public double TotalTime { get; private set; } /// summary运动方向符号 1正向 -1反向/summary private double _dirSign; /// summary基准规划位移始终正数/summary private double _baseDist; #region 当前实时状态 public enum MotionState { Idle, Running, Finished } public MotionState State { get; private set; } /// summary已运行时间/summary public double ElapsedTime { get; private set; } /// summary当前输出目标位置/summary public double CurrentPos { get; private set; } /// summary当前速度/summary public double CurrentVel { get; private set; } /// summary当前加速度/summary public double CurrentAcc { get; private set; } #endregion /// summary /// 启动一次S曲线运动规划 /// /summary /// param nametargetDist目标位移/param /// param namevMax最大速度/param /// param nameaMax最大加速度/param /// param namejMax最大加加速度Jerk/param public void StartMotion(double targetDist, double vMax, double aMax, double jMax) { //参数合法性校验 if (Math.Abs(targetDist) 1e-12) { State MotionState.Finished; CurrentPos 0; CurrentVel 0; CurrentAcc 0; return; } if (vMax 0 || aMax 0 || jMax 0) throw new ArgumentException(速度、加速度、Jerk必须大于0); TargetDistance targetDist; VMax vMax; AMax aMax; JMax jMax; _dirSign targetDist 0 ? 1.0 : -1.0; _baseDist Math.Abs(targetDist); //核心预规划求解各阶段时间 PlanProfileTime(); ElapsedTime 0; State MotionState.Running; } /// summary /// 每控制周期调用更新运动状态 /// /summary /// param namedt本次周期时间增量秒/param public void Update(double dt) { if (State ! MotionState.Running) return; ElapsedTime dt; if (ElapsedTime TotalTime) { CurrentPos TargetDistance; CurrentVel 0; CurrentAcc 0; State MotionState.Finished; return; } CalcInstantMotion(ElapsedTime, out double sBase, out double v, out double a); CurrentPos sBase * _dirSign; CurrentVel v * _dirSign; CurrentAcc a * _dirSign; } /// summary /// 停止当前运动 /// /summary public void Stop() { State MotionState.Idle; ElapsedTime 0; CurrentPos 0; CurrentVel 0; CurrentAcc 0; } #region 核心规划算法求解T1~T7 private void PlanProfileTime() { double Tj AMax / JMax; //达到最大加速度所需时间 //完整加速段(123)能达到的速度 double vPeakFull JMax * Tj * Tj; double sAccFull JMax * Tj * Tj * Tj; //完整加速区间位移 double tAccTotal; double vReach; if (vPeakFull VMax) { //情况1可以达到最大加速度 if (VMax vPeakFull) { T1 Tj; T2 0; T3 Tj; vReach vPeakFull; } else { T1 Tj; T3 Tj; double deltaV VMax - vPeakFull; T2 deltaV / AMax; vReach VMax; } tAccTotal T1 T2 T3; } else { //情况2无法达到Amax没有匀加速段 T20 T2 0; double tHalf Math.Sqrt(VMax / JMax); T1 tHalf; T3 tHalf; vReach VMax; tAccTotal T1 T3; } //计算加速段总位移 double sAcc CalcSegmentDistance(tAccTotal); double sDec sAcc; //对称减速 double sSumAccDec sAcc sDec; if (sSumAccDec _baseDist) { //存在匀速段 double sUniform _baseDist - sSumAccDec; T4 sUniform / vReach; T5 T3; T6 T2; T7 T1; } else { //行程不足无匀速段 T40需要重新裁剪峰值速度 T4 0; double sNeed _baseDist / 2.0; //二分法求解实际能够到达的峰值速度 double vLow 0; double vHigh vReach; for (int i 0; i 100; i) { double vMid (vLow vHigh) / 2; double sTest CalcAccDistanceByVMax(vMid); if (sTest sNeed) vLow vMid; else vHigh vMid; } double vActual (vLow vHigh) / 2; //重新根据受限峰值速度更新T1 T2 T3 if (vActual JMax * Tj * Tj) { T1 Tj; T3 Tj; double dv vActual - JMax * Tj * Tj; T2 dv / AMax; } else { T2 0; double th Math.Sqrt(vActual / JMax); T1 th; T3 th; } T5 T3; T6 T2; T7 T1; } TotalTime T1 T2 T3 T4 T5 T6 T7; } /// summary根据指定峰值速度计算单侧加速段位移/summary private double CalcAccDistanceByVMax(double vTarget) { double Tj AMax / JMax; double vFull JMax * Tj * Tj; double s; if (vTarget vFull) { double dv vTarget - vFull; s JMax * Tj * Tj * Tj dv * Tj 0.5 * AMax * (dv / AMax) * (dv / AMax); } else { double t Math.Sqrt(vTarget / JMax); s JMax * t * t * t / 3.0; } return s; } /// summary计算加速阶段总位移用于完整7段预判/summary private double CalcSegmentDistance(double tTotalAcc) { double t1 T1; double t2 T2; double t3 T3; double s1 JMax * t1 * t1 * t1 / 6.0; double v1 0.5 * JMax * t1 * t1; double s2 v1 * t2 0.5 * AMax * t2 * t2; double v2 v1 AMax * t2; double s3 v2 * t3 AMax * t3 * t3 / 2.0 - JMax * t3 * t3 * t3 / 6.0; return s1 s2 s3; } #endregion #region 根据当前时刻t求解位移、速度、加速度解析多项式 private void CalcInstantMotion(double t, out double s, out double v, out double a) { double tSum 0; double tSeg; s 0; v 0; a 0; //1.加加速 T1 tSeg T1; if (t tSum tSeg) { double dt t - tSum; a JMax * dt; v 0.5 * JMax * dt * dt; s JMax * dt * dt * dt / 6.0; return; } s JMax * tSeg * tSeg * tSeg / 6.0; v 0.5 * JMax * tSeg * tSeg; a AMax; tSum tSeg; //2.匀加速 T2 tSeg T2; if (t tSum tSeg) { double dt t - tSum; a AMax; v AMax * dt; s v * dt - 0.5 * AMax * dt * dt; return; } s v * tSeg 0.5 * AMax * tSeg * tSeg; v AMax * tSeg; tSum tSeg; //3.减加速 T3 tSeg T3; if (t tSum tSeg) { double dt t - tSum; a AMax - JMax * dt; v AMax * dt - 0.5 * JMax * dt * dt; s v * dt - 0.5 * AMax * dt * dt JMax * dt * dt * dt / 6.0; return; } s v * tSeg AMax * tSeg * tSeg / 2.0 - JMax * tSeg * tSeg * tSeg / 6.0; tSum tSeg; a 0; //4.匀速 T4 tSeg T4; if (t tSum tSeg) { double dt t - tSum; s v * dt; return; } s v * tSeg; tSum tSeg; //5.加减速 T5 tSeg T5; if (t tSum tSeg) { double dt t - tSum; a -JMax * dt; v - 0.5 * JMax * dt * dt; s v * dt JMax * dt * dt * dt / 6.0; return; } s v * tSeg - JMax * tSeg * tSeg * tSeg / 6.0; v - 0.5 * JMax * tSeg * tSeg; tSum tSeg; a -AMax; //6.匀减速 T6 tSeg T6; if (t tSum tSeg) { double dt t - tSum; a -AMax; v - AMax * dt; s v * dt 0.5 * AMax * dt * dt; return; } s v * tSeg - 0.5 * AMax * tSeg * tSeg; v - AMax * tSeg; tSum tSeg; //7.减减速 T7 tSeg T7; if (t tSum tSeg) { double dt t - tSum; a -AMax JMax * dt; v (-AMax) * dt 0.5 * JMax * dt * dt; s v * dt 0.5 * AMax * dt * dt - JMax * dt * dt * dt / 6.0; return; } } #endregion }调用示例class Program { static void Main(string[] args) { SCurveProfile profile new SCurveProfile(); //参数目标位移1000脉冲最大速度500pulse/s最大加速度2000Jerk10000 profile.StartMotion(1000, 500, 2000, 10000); double cycleTime 0.001; //1ms控制周期 while (profile.State SCurveProfile.MotionState.Running) { profile.Update(cycleTime); Console.WriteLine($Time{profile.ElapsedTime:F4} Pos{profile.CurrentPos:F2} Vel{profile.CurrentVel:F2}); } Console.WriteLine(运动完成); } }S型加减速曲线的优缺点分析优点加速度连续平滑S型加减速曲线实现了加速度的连续变化加加速度Jerk有界避免了梯形加减速中加速度突变的问题。这种平滑特性有效抑制了机械振动和冲击特别适用于CNC机床加工可防止因加速度突变导致的刀具震颤。延长机械寿命通过减少运动过程中的冲击和振动S型曲线能显著降低丝杆、导轨、联轴器等精密传动部件的磨损。实验表明采用S型曲线可使关键部件的使用寿命延长30-50%尤其适合频繁启停或高速运行的自动化设备。提高定位精度在高速启停工况下S型曲线通过平滑的速度过渡可减少60-80%的振荡幅度和超调量适用于半导体设备、医疗仪器等对微米级定位精度要求严格的场合。解析解计算优势S型加减速基于完全解析的数学解法避免了积分控制的累积误差确保了运动控制的精确性和可重复性。参数化配置灵活通过调整最大速度Vmax、最大加速度Amax和最大加加速度Jmax三个参数可适配不同刚性程度的负载设备。例如重型设备可降低Jmax值而高速轻载设备则可提高Amax值。缺点算法复杂度较高相比梯形加减速S型曲线的运动规划逻辑更复杂需处理7个运动阶段的转换条件加加速、匀加速、减加速、匀速、加减速、匀减速、减减速。参数调试门槛高需协调位移、Vmax、Amax、Jmax四个关键参数的相互关系。若Jmax设置不当可能导致实际加速度峰值无法达到设定值通常需要借助专业调试软件优化参数。运动时间略长在相同最大速度下由于增加了加速度变化过程S型曲线完成相同位移的运动时间比梯形曲线长约5-15%可能影响对节拍时间要求极高的应用如高速分拣。对控制器要求较高虽然现代CPU/MCU如Cortex-M4及以上内核的浮点运算能力足以支持实时计算但对于老旧的8位或16位控制器处理S型曲线的各阶段参数仍可能带来一定负担。适用场景✅ 推荐使用场景高精度、低振动要求伺服 CNC 机床与雕刻机适用于高精度加工场景如金属切削、复杂曲面雕刻等。伺服系统支持平滑加减速减少机械振动提升加工表面质量。示例五轴联动 CNC 机床加工航空零部件时伺服系统能实现精准轨迹控制。机器人关节与线性模组适用于自动化产线的精密装配、搬运或焊接任务。伺服驱动可实现快速响应和精准定位减少运动抖动。应用场景工业机器人抓取电子元件时避免振动导致的放置偏差。龙门搬运系统适合重型或高精度搬运如大型工件定位或机床上下料。伺服驱动确保大惯量负载下的平稳启停防止设备冲击损坏。示例汽车制造中龙门搬运系统需精准将车身部件送至装配工位。半导体设备与液晶面板搬运适用于对振动敏感的高精密环境如晶圆传输或面板对位。伺服系统可实现纳米级定位避免微振动影响产品良率。典型场景光刻机中晶圆台的精密运动控制。3D 打印机高端机型与激光切割设备适合复杂路径规划和高速高精度运动场景。伺服系统减少打印或切割时的层间错位提升成品质量。示例金属 3D 打印机在烧结过程中需保持激光头稳定运动。摄影滑轨与视觉运动平台适用于影视拍摄或视觉检测中的平滑移动需求。伺服驱动实现无顿挫匀速运动避免画面抖动或检测误差。应用场景高速相机拍摄运动物体时滑轨需同步精准跟踪。❌ 可简化使用梯形加减速的场景低精度、高刚性需求低速步进输送机构适用于低速、负载简单的传输场景如流水线分拣或低速传送带。梯形加减速即可满足启停需求无需复杂控制算法。示例食品包装线上的低速传送带仅需简单启停控制。简单传送带系统用于负载固定、无精密定位要求的物料传输。梯形加减速降低成本且刚性结构可容忍一定冲击。典型场景仓库中的箱体搬运传送带。负载刚性极强且允许冲击的场景适用于机械结构本身能吸收冲击的设备如冲压机或锻造设备。定位精度要求不高时梯形加减速可简化控制系统设计。示例金属板材冲孔机短暂冲击不影响加工质量。定位精度要求不高的通用设备如农业机械、普通包装机等运动误差容忍度较高。梯形加减速足以满足基本运动需求性价比更优。应用场景化肥填充机的简单开合控制。总结S 曲线加减速算法是运动控制架构中的上层轨迹生成模块位于控制流程的最前端。该算法通过限制加加速度Jerk采用分段三次多项式构造平滑的速度曲线有效解决了传统梯形加减速带来的机械冲击问题。算法采用两层架构设计离线预规划阶段和实时解析求值阶段。其中短行程工况下的阶段自动裁剪逻辑是代码实现的主要难点。本文基于 C# 实现了纯解析求解方案具有以下特点无需依赖缓冲区或离线点位表支持周期性实时调度既适用于 PC 端上位机轨迹生成也可通过语法精简移植到嵌入式 C 平台最终生成的轨迹位置指令将被传输至下层位置环 PID 控制器形成完整的闭环运动控制系统。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门