有一阵子我在现场调一条改造产线,电机带着托辊从0冲到50Hz,用的是普通斜坡加减速。设备空跑一切正常,一旦带料,减速过程整个机架“咯噔”一声闷响,托辊上的料都能颠出去。后来把加减速曲线换成S型,问题一下就没有了。从那以后,凡是用变频器驱动的设备,只要对机械冲击有要求,我都直接在S7-1200/1500上用SCL写一个S型速度曲线发生器,不再依赖变频器自带的斜坡功能。
这篇主要讲清楚三件事:为什么S型曲线能解决冲击问题、在S7-1200/1500里怎么用SCL把曲线写出来、以及现场配套变频器调试时最容易踩的坑。适合正在做变频器控制、设备启停冲击大、或者想摆脱“梯形斜坡”的电气工程师和PLC调试人员。
1. 为什么非要用S型速度曲线
1.1 一次带载试车让我盯上了这条曲线
那条产线的主传动是7.5kW电机,变频器驱动,负载是托辊加布料。原程序是在PLC里做了个斜坡函数发生器,把给定速度按照固定斜率从0升到目标值,停机时再按固定斜率降回0。启动时听起来还行,只是电流有点冲,真正暴露问题的是停机段:到了减速后期,设备像被什么东西拽了一下,然后整个机架震一下,偶尔还会触发机械过载报警。
我一开始以为是变频器减速时间太短,把减速时间从5秒拉到8秒,震动确实小了一点,但还是在某个速度点附近出现明显抖动。后来用示波器看变频器输出电流波形才发现,问题根本不在减速时间长短,而是“加速度突变”造成的机械冲击。
梯形曲线在速度-时间图上是斜直线,斜率就是加速度。启动瞬间,速度从0突然变成“有斜率”,加速度从0瞬间跳到最大值;减速结束瞬间,速度从“有斜率”突然变成0,加速度又从最大值瞬间跳到0。这两个跳变点,就是机械冲击的来源。负载越重、惯量越大,冲击越明显。
1.2 梯形曲线的病灶:加速度突变到底有多痛
很多老工程师习惯直接在变频器里设加速时间和减速时间,因为变频器自带的斜坡大部分也是直线斜坡。对于风机、水泵这类负载,直线斜坡问题不大;但碰到大惯量设备、起重行走机构、桁架机械手、或者对动平衡有要求的旋转设备,直线斜坡的“硬起硬停”就会变成机械结构的老化加速器。
从控制角度讲,速度曲线不仅要保证速度连续,还要保证加速度连续,甚至加速度的变化率连续。梯形曲线只保证了速度连续,加速度在四个拐点处全是断的。设备启动瞬间,电机输出的力矩要立即克服静摩擦和惯量,传动间隙会被“砸开”;停机瞬间,负载动能要在极短时间内被制动吸收,机械连接处就会发出闷响。
S型曲线解决的就是这个问题:速度从0开始变化时,加速度也从0开始慢慢增加,到达中点附近加速度最大,然后再慢慢减小到0。整个过程没有加速度阶跃,传动系统的受力变化是渐进的,冲击自然小很多。
1.3 S型曲线的数学直觉:加速度别“跳”就行
S型曲线的名字很形象,速度-时间图像像字母S,先缓慢上升,然后加速变快,接近目标时又放缓。最直观的理解是:把一个方波形状的加速度曲线“圆滑”掉,变成梯形甚至三角形。
工程中最常用的实现方式有两种。
一种是正弦过渡法:在加速段让速度按照
v(t) = v_start + (v_target - v_start) × [1 - cos(π × t / T)] / 2
来变化。t=0时,速度变化率为0,加速度为0;t=T时,速度刚好到达目标值,变化率也是0。最大加速度出现在时间中点,前后对称。这个公式写起来短,效果够用,也是我推荐的首选。
另一种是分段多项式法,把加速段拆成“加加速—匀加速—减加速”三段,理论上更接近教科书里的S型曲线,但代码量和调参复杂度都高一些,后面我会给出公式,但一般项目用正弦过渡法就够了。
生活里最好的类比就是开车:梯形曲线等于起步直接踩死油门,到了目标速度再瞬间松开;S型曲线等于先轻踩油门,等车速起来一点再逐渐加深,接近目标速度时缓缓收油门。乘客的体感完全不同。
2. 整体方案选型与FB接口设计
2.1 为什么要在PLC上自己生成曲线
有人会问:现在变频器基本都有S曲线功能,直接在变频器里设S斜坡时间不就行了?答案是:很多场合确实可以,但用PLC做曲线有几个明显优势。
第一,参数可以随时通过HMI修改。变频器里的S曲线参数藏在菜单深处,现场操作工根本不会去动;把加减速时间和S程度做到触摸屏上,调试时改起来非常方便。
第二,曲线和逻辑可以统一。比如设备有多个速度档位,不同档位需要不同的加减速时间,用PLC可以做到“目标速度一变,曲线立即重新规划”,而变频器内部逻辑往往只有一个斜坡时间,切档时容易跳变。
第三,后续如果想扩展定位控制、同步控制,PLC侧已经有了速度给定的数学模型,在此基础上加位置闭环计算会顺滑很多。
2.2 给定通道选型:模拟量、Modbus还是PROFINET
曲线算出来之后,总要把速度给定交给变频器。有三种常见通道,选择时需要考虑更新周期和抗干扰能力。
| 通道类型 | 更新周期 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 模拟量0~10V/4~20mA | PLC扫描周期+硬件转换延时 | 接线简单,适配所有变频器 | 精度一般,易受干扰 | 中小功率、对平滑度要求不高的设备 |
| Modbus RTU | 50~200ms轮询周期 | 改参数方便,不用AO模块 | 周期不稳定,曲线容易台阶化 | 预算有限、速度精度不敏感 |
| PROFINET/PROFIBUS周期IO | 与PLC周期同步 | 刷新快,稳定,支持报文控制字 | 需要驱动器支持总线通讯 | 大功率、高动态响应、曲线平滑度要求高 |
我自己的习惯是:能用PROFINET就用PROFINET,其次选模拟量,Modbus RTU放最后。原因很简单,S型曲线的平滑度很大程度上取决于给定值的刷新频率。PROFINET的IO数据可以做到和PLC扫描周期同步刷新,实际效果接近于连续曲线;Modbus轮询一抖一抖的,本来很平滑的S曲线会变成阶梯状,现场听起来电机声音都是一顿一顿的。
如果手里只有普通变频器,那就走模拟量。只要把PLC侧AO通道的输出滤波关掉或者调小,加上变频器侧内部斜坡设得足够短,效果也够用。
2.3 定时中断是底线,别用主扫描循环攒时间
这是整个方案里最容易被忽略,却又最关键的一步。
SCL代码生成S型曲线,本质上是一个“按时间推进的计算过程”。每个固定周期执行一次,时间变量累加一次,然后根据当前时间和总时间算出当前速度。这个“固定周期”必须来自真正的定时中断,而不是主扫描循环OB1。
为什么不能用OB1?因为PLC主扫描周期不是恒定的,程序量、通讯负载、HMI访问都会让扫描时间在几毫秒到几十毫秒之间波动。同样一个加速过程,第一次扫描周期是5ms,第二次变成12ms,每次循环累加的dt都不一样,生成的速度曲线会忽快忽慢,现场表现就是电机运转声音不平稳,加速时一顿一顿。
正确做法是新建一个循环中断组织块,比如OB30,把循环时间设为100ms,然后把曲线计算代码放在这个中断块里调用。这样无论OB1扫描周期怎么变,曲线计算永远是每100ms执行一次,dt恒定,曲线质量就有保证。
如果你的控制精度要求更高,可以把OB30循环时间改成50ms甚至20ms。但注意,循环中断执行期间会打断主程序,配置得太短会挤占CPU资源,一般100ms对变频器速度控制来说已经完全够用。
2.4 FB的输入输出定义:一张表看清接口
整体方案定型之后,我一般先画FB接口,再写内部逻辑。这个功能块建议做成FB,而不是FC,因为需要背景数据块保存当前速度、运行状态等内部变量。
接口定义如下:
| 接口 | 类型 | 说明 |
|---|---|---|
| bEnable | BOOL | 运行使能,上升沿启动爬坡,下降沿开始减速停车 |
| rSetTarget | REAL | 目标速度,单位%,例如50.0表示50%额定频率 |
| rAccelTime | REAL | 加速时间,单位秒,从当前速度爬到目标速度的总时间 |
| rDecelTime | REAL | 减速时间,单位秒,从当前速度减速到0的总时间 |
| rMaxLimit | REAL | 输出上限,默认100%,用于限制最高速度 |
| rOutSpeed | REAL | S型曲线计算后的速度给定值,单位% |
| nState | INT | 状态输出,0=停止,1=爬坡中,2=匀速运行 |
这个接口设计做了两个刻意的处理。一是把加减速时间和目标速度都做成输入,方便后期接到HMI或者配方数据;二是输出直接给百分比,适配模拟量和通讯两种通道,换算到具体频率的活留给输出扫描块去干。
3. SCL核心算法与代码实现
3.1 正弦过渡法为什么够用
我最早用的是严格的三段式S曲线,代码写了几个IF分支,调参的时候又要把加加速比例、匀加速比例分开设,现场工人完全看不懂。后来发现,用余弦函数做速度过渡,效果上已经非常接近“标准S曲线”,但代码量只有三段式的三分之一。
正弦过渡法的本质是:用一段余弦曲线的“半波”代替直线斜坡。速度从起点到终点,先慢后快再慢,起点和终点的斜率为0,最大斜率出现在时间中点。加速度的峰值是完全可控的,而且不会像梯形曲线那样出现阶跃。
对于大多数变频器驱动的电机负载,正弦过渡法和教科书上的分段S曲线在机械冲击上的差异,人耳基本听不出来。所以我建议先正弦法,如果项目有特殊要求再上三段式。
3.2 完整FB代码抄作业版
下面这段代码可以直接复制到TIA Portal里的FB中,建议配合OB30循环中断使用,OB30循环时间设100ms。
FUNCTION_BLOCK "FB_SpeedRamp" { S7_Optimized_Access := 'TRUE' } VERSION : 0.1 VAR_INPUT bEnable : BOOL; // 运行使能 rSetTarget : REAL; // 目标速度,单位:% rAccelTime : REAL; // 加速时间,单位:秒 rDecelTime : REAL; // 减速时间,单位:秒 rMaxLimit : REAL; // 输出上限,单位:% END_VAR VAR_OUTPUT rOutSpeed : REAL; // S型曲线后的速度给定,单位:% nState : INT; // 0=停止 1=爬坡中 2=匀速运行 END_VAR VAR rCurSpeed : REAL; // 当前计算速度 rStartSpeed : REAL; // 本次爬坡起始速度 rRampTarget : REAL; // 本次爬坡目标速度 rRampTime : REAL; // 本次爬坡总时间 rT : REAL; // 本次爬坡已运行时间 bPrevEnable : BOOL; // 上一次使能状态,用于上升沿检测 END_VAR VAR CONSTANT cDt : REAL := 0.1; // 调用周期,100ms循环中断 cPi : REAL := 3.14159265; END_VAR BEGIN // 使能上升沿:启动爬坡 IF bEnable AND NOT bPrevEnable THEN IF rSetTarget > 0.1 THEN nState := 1; rRampTarget := rSetTarget; rRampTime := rAccelTime; rT := 0.0; rStartSpeed := rCurSpeed; END_IF; END_IF; // 使能消失:开始减速停车 IF NOT bEnable THEN IF nState <> 0 THEN nState := 1; rRampTarget := 0.0; rRampTime := rDecelTime; rT := 0.0; rStartSpeed := rCurSpeed; END_IF; END_IF; // 匀速运行中,目标速度改变则重新规划曲线 IF bEnable AND nState = 2 THEN IF ABS(rSetTarget - rCurSpeed) > 0.1 THEN nState := 1; rRampTarget := rSetTarget; IF rSetTarget > rCurSpeed THEN rRampTime := rAccelTime; ELSE rRampTime := rDecelTime; END_IF; rT := 0.0; rStartSpeed := rCurSpeed; END_IF; END_IF; // 状态机主体 CASE nState OF 0: // 停止 rCurSpeed := 0.0; 1: // 爬坡中:按正弦过渡公式计算速度 rT := rT + cDt; IF rT >= rRampTime THEN rCurSpeed := rRampTarget; IF rRampTarget <= 0.0 THEN nState := 0; ELSE nState := 2; END_IF; ELSE rCurSpeed := rStartSpeed + (rRampTarget - rStartSpeed) * (1.0 - COS(cPi * rT / rRampTime)) / 2.0; END_IF; 2: // 匀速运行 rCurSpeed := rSetTarget; END_CASE; // 输出限幅 IF rCurSpeed > rMaxLimit THEN rCurSpeed := rMaxLimit; END_IF; IF rCurSpeed < 0.0 THEN rCurSpeed := 0.0; END_IF; rOutSpeed := rCurSpeed; bPrevEnable := bEnable; END_FUNCTION_BLOCK3.3 逐段解释代码逻辑
很多刚接触SCL的同行拿到代码第一反应是:为什么不用定时器TONR?因为在这里,时间变量rT是每个中断周期累加一次cDt,而不是依赖TONR的使能信号。好处是逻辑清晰,方便在任意时刻重新清零和赋值,不会因为定时器复位条件写错导致奇奇怪怪的问题。
使能上升沿那段,关键是“rStartSpeed := rCurSpeed”。这意味着如果上次停车停在50%,这次启动目标是80%,曲线会从50%平滑爬到80%,而不是先掉回0再爬。这对于频繁启停的工艺很友好。
使能消失那段,把rRampTarget强制改为0,然后继续用正弦公式,但这次的时间是rDecelTime。这就是减速曲线,和加速曲线完全对称。
匀速运行中目标改变的处理,很多人会忽略。如果不处理,运行中HMI把速度从50%改成80%,那rCurSpeed会直接跳到80%,现场就是一次阶跃扰动,之前在做的S型全白费。所以必须在匀速状态检测目标变化,重新进入爬坡状态。
状态机里最核心的公式只有一行:
rCurSpeed := rStartSpeed + (rRampTarget - rStartSpeed) * (1.0 - COS(cPi * rT / rRampTime)) / 2.0;
当rT为0时,COS(0)=1,整个括号值为0,输出等于起点速度;当rT等于rRampTime时,COS(π)=-1,括号值为1,输出等于目标速度。中点的变化率最大,而且前后对称。
3.4 想用更标准的三段式S曲线?公式和写法在这
虽然正弦法够用,但万一遇到要求严格的场合,可以把公式换成下面的分段形式。
设总爬坡时间为T,取前段比例a,一般a取0.25~0.3。则:
最大加速度 Amax = Δv / [T × (1 - a)]
其中Δv = 目标速度 - 起始速度。
然后分三段计算速度:
0 ≤ t ≤ aT 时,v(t) = v_start + (Amax / (2 × a × T)) × t²
aT ≤ t ≤ (1-a)T 时,v(t) = v_start + (Amax × a × T / 2) + Amax × (t - a × T)
(1-a)T ≤ t ≤ T 时,v(t) = v_start + Δv - (Amax / (2 × a × T)) × (T - t)²
写成SCL,就是在爬坡分支里按rT所处的区间选择对应的计算公式。三段式的特点是有明显的“匀加速”段,速度曲线中段是直线,启动和结束的圆滑段更短,适合对加工节拍有要求、想尽可能缩短加减速时间又不希望冲击太大的场合。
对于一般的变频器调速,我仍然建议先用正弦过渡法,把系统跑顺了再考虑要不要精细化。
4. 变频器侧参数与硬件配套
4.1 模拟量通道组态与标定换算
如果走模拟量给定,PLC侧需要组态AO模块。S7-1200本身不带模拟量输出,一般要加SM1232模拟量输出模块。在TIA Portal里把通道组态成电压0~10V或者电流4~20mA,对应整定值0~27648。
换算的套路很固定:把FB输出的百分数(0~100%)转成整定值(0~27648),再写到QW输出地址。可以写在一个简单的FC里,或者在OB1里用SCL三行搞定:
#RawValue := REAL_TO_INT(("HMI_Speed" / 100.0) * 27648.0); "Output_Analog".QW0 := INT_TO_WORD(#RawValue);如果变频器的最大频率不是50Hz,比如是60Hz,需要把百分比和频率的关系在HMI或PLC里先换算一次。我的习惯是FB输出直接用百分数,因为这样和模拟量、通讯报文的百分比刻度天然对齐,省得在曲线计算里掺频率单位。
模拟量线路的走线要特别注意:信号线用屏蔽双绞线,屏蔽层单端接地,尽量远离动力线和变频器输出线。变频器侧很多默认把AI通道的滤波时间设得比较大,比如0.5秒,这会明显拉低PLC侧S曲线的响应,需要在变频器参数里把AI滤波时间调到最小。
4.2 变频器斜坡时间必须“让位”
这个坑我踩过好几次,必须单独拎出来说。
如果PLC侧已经做了S型曲线,变频器内部还有一组自己的斜坡时间,那最终电机得到的速度就是两层斜坡叠加后的结果。PLC的S曲线上升段,变频器内部直线斜坡会再限制一次变化率,导致实际速度曲线在启动时被“压扁”,然后中途又追不上PLC给定的速度,最终可能变成一个畸变的曲线,有时看起来反而比单纯使用梯形曲线更别扭。
正确做法是:把变频器的加速时间和减速时间都设得很短,短到不影响PLC给出的曲线。通常设成0.2~0.5秒。这个时间不是0,是为了过滤模拟量信号里微小的噪声波动,避免电机因为给定值的毛刺来回抖动。
使用PROFINET或Modbus通讯时也是同理,变频器侧的斜坡功能要么关闭,要么设到最小。让PLC的S型曲线成为唯一的斜坡环节,控制链路上只有一个“积分器”,系统特性才可控。
4.3 安全联锁和急停别走S曲线
这一点比算法本身更重要。
S型曲线只用于正常启动和正常停车的平滑过渡。紧急停机、安全回路断开、光幕触发、操作工拍急停,这些情况必须直接切断变频器的使能信号,或者走变频器的快速停车/自由停车功能,绝不能让S曲线慢慢爬下来。
原因很简单:S曲线本质是“有时间延时的减速”,急停场景下时间就是生命。设备还在按曲线减速的过程中,可能已经撞机了。
我的程序结构是:S型曲线FB只管速度给定值的生成;另有一条独立的急停逻辑,直接作用于变频器的数字量输入端子或者通讯控制字里的“OFF2/OFF3”位。两者互不干扰,急停优先级永远最高。
5. 现场调试实录与常见问题排查
5.1 一套从零开始的调试流程
拿到现场,我建议按下面的顺序来,别一上来就满载跑S曲线。
第一步,确认接线和通道。模拟量输出模块的端子电压,用万用表量一下,看PLC强制输出50%时是不是对应5V或12mA。通讯方式则先确认报文有没有建立,控制字能不能启停。
第二步,空载试转。把电机和负载脱开,目标速度设20%,加速时间给大一点,比如8秒,跑一次完整的启停,听电机声音是否平稳,看电流是否在加速中点附近缓慢上升、没有尖峰。
第三步,带载试转。目标速度50%,加减速时间按设备工艺要求设定。重点听减速段有没有闷响,看设备有没有震动。
第四步,微调时间。如果启动还是有冲击,优先增加加速时间,不要动S曲线的算法。一般加速时间增加30%,冲击会明显下降。如果减速停车最后一段有爬行,参考下面的问题二处理。
第五步,固定参数。把调好的参数写进HMI或者配方,锁屏,防止现场误改。
5.2 问题一:启动瞬间电流冲高甚至过流
现象:启动刚开始时,变频器输出电流突然冲到很高,甚至报过流。
排查顺序:先看加速时间是不是太短。S型曲线虽然平滑了加速度,但总时间太短意味着加速度峰值很大,同样会过流。把加速时间拉长一档再试。
再看变频器内部斜坡时间。如果变频器加速时间设得比PLC曲线时间长,那么PLC输出已经到30%了,变频器还慢吞吞地跟,速度差积久了就容易过流。把变频器斜坡时间压到0.3秒以下。
最后看模拟量通道滤波。如果滤波时间太大,给定信号滞后严重,速度差值动态拉大,也会造成电流波动。这个在变频器参数里把AI滤波时间调小即可。
5.3 问题二:停机时最后一段爬行不停
现象:减速到接近零速时,速度变化极慢,电机像“挂”在那里一样,迟迟停不下来。
这是正弦公式的固有特性。余弦过渡在接近末端时,速度变化率趋向于0,所以最后5%到0的阶段会非常“肉”。如果工艺要求停车干脆利落,可以在速度降到某个阈值以下后切换成线性斜坡,或者直接给零速。
我常用的办法是:在减速阶段加一个判断,如果rCurSpeed小于5.0(百分数),就让速度按一个更短的线性时间直接归零。这不是数学上最平滑的做法,但现场设备停下来干脆,操作工就不会抱怨“停车磨叽”。
另一种更稳妥的办法是减速到2%左右时,直接给变频器发一个自由停车信号,让电机靠惯性自然停。这种方法适合对停车位置没有要求的普通传动设备。
5.4 问题三:给定曲线出现台阶或毛刺
现象:电机运行声音一顿一顿,用软件看给定速度,是一条楼梯状的线,而不是光滑的S曲线。
先说台阶。如果走的是Modbus RTU,那大概率是通讯轮询周期太长了。每个速度刷新周期之间,给定值停留在旧值,下一次更新才跳到新值,曲线看起来就是台阶。解决办法要么升级成PROFINET,要么把Modbus轮询周期压缩到50ms以内,并且确保PLC扫描周期和轮询周期匹配。
再说毛刺。多半是模拟量信号受干扰或者AO输出滤波没关。把模拟量线重新走线,屏蔽层单端可靠接地,在变频器侧或者PLC侧把输出滤波稍微加一点,但不要加太多,否则滞后又来了。
如果是S7-1500,可以用TIA Portal自带的逻辑分析器Trace功能,直接抓取FB输出的rOutSpeed曲线,非常直观。S7-1200没有Trace,可以用HMI的趋势控件,或者干脆把rOutSpeed每周期写到数据日志里,跑完一段再导出来看。没有条件的情况下,我试过用PLCSIM仿真跑曲线看趋势,效果也不错。
5.4 问题四:重启时速度从0跳变
现象:设备停在50%的中间状态,重新给使能后,速度不是从50%平滑爬升,而是先掉到0再爬,或者直接从0阶跃到50%。
这种情况往往是对“rStartSpeed”的初始化没处理好。第一次上电或者FB被复位后,rCurSpeed默认是0,如果程序里没有在每次停车后强制把rCurSpeed清零,下次启动时的起始速度就会残留上一次的值。
我的处理策略是:状态0里强制rCurSpeed := 0.0,同时把rStartSpeed也初始化为0。这样不管上一次是急停还是正常停车,一旦状态回到0,下一次爬坡一定从0开始,不会出现诡异跳变。如果工艺上确实需要“从当前实际速度继续爬坡”,那就要引入编码器反馈,用它来初始化rStartSpeed,而不是用内部变量。
最后再说两句实在话
把S型曲线写进PLC只是第一步,真正值钱的部分是现场调试时的“手感”。我吃过很多亏之后总结出一个笨办法:所有加减速时间,先给一个明显偏大的值,比如目标速度100%时加速时间给10秒,跑通全流程,确认机械没有异常,再逐步压缩时间,每次压20%左右,直到刚好出现轻微冲击感就退回上一档。这样调出来的参数既保证了效率,又留了安全余量。
这个FB后来被我复制到了好几个项目里,从S7-1200到S7-1500都能跑,只是5000字提醒有点短,不够展开太多。如果有机会,后续我还可以聊聊怎么把同样的算法延伸到伺服定位系统里,让位置曲线也带上S型过渡。现在先记住最核心的一句话:曲线只是一个数字,但设备舒不舒服,全看你有没有把这个数字的“脾气”摸透。