简介:面向自动化专业学生、机器人研发工程师及希望掌握Simulink仿真技术的读者,这份文档围绕直流电机速度控制系统的建模、仿真与参数调优展开,可服务于传送带驱动、精密定位等需要恒定转速输出的场景。内容按系统建模、PID控制器设计、速度传感器建模、仿真验证和性能优化五个阶段组织,结合直流电机动力学方程、控制器代码与Simulink模型搭建示例,说明如何通过调整比例、积分、微分参数改善稳定性和响应速度,并给出负载扰动与测量噪声下的验证思路。资源包共1个docx文件,约24KB,篇幅精炼,适合作为课程设计或工程原型的参考资料。目前已有271人学习,读者可从中获取从模型建立到参数整定的完整流程、可复用代码片段以及性能调优的排查方向。
1. 直流电机速度控制在 Simulink 里到底能跑出什么
传送带要保持恒定线速度,机器人关节要按轨迹走,这两类活最后都会归到同一个问题:给一个电压,直流电机的转速能在多长时间内、以多大误差稳到目标值。基于 Simulink 的直流电机速度控制系统仿真,本质是把这个问题先在数字域里跑一遍——电机本体用状态方程描述,PID控制器负责纠偏,速度传感器带量化误差和噪声,负载转矩随时能改。它适合两类人:做课程设计、要把论文里那张阶跃响应曲线跑出来的学生,和已经在做电机驱动、想在改硬件和烧板子之前先把参数摸清楚的工程师。整套东西不依赖任何实物,装了 MATLAB/Simulink 的机器就能从头跑到尾。
真正让人卡住的地方往往不在 PID 三个字母上。参数标定错一个数量级,曲线形状全变;求解器步长没跟上电气时间常数,波形会指数发散;传感器反馈纯净得像教科书,调出来的参数一上真机就崩。下面按“建模—控制器—传感器—排查—批处理”的顺序拆,每一步都给能直接抄的参数和代码。
2. 把电机微分方程搬进 Simulink:参数标定、标量端口与求解器选型
2.1 先手算两个时间常数,再决定建模粒度
直流电机的两状态模型是标准形式,状态取电枢电流i和角速度omega:
di/dt = (v - Kb*omega - R*i) / L domega/dt = (Kt*i - B*omega - Tl) / J七个参数里,R和L用万用表或 LCR 表能直接量,Kt和Kb在 SI 单位制下数值相等——因为电磁功率Kt*omega*i和反电动势功率Kb*omega*i是同一个量,这一点能省掉一次单独辨识。J和B最麻烦,一般靠实测阶跃响应反推,或者从转子惯量加负载折算估。
我一般会先用这么一组自洽的小功率电机参数打底:
| 参数 | 含义 | 取值 | 单位 |
|---|---|---|---|
| R | 电枢电阻 | 1.2 | Ω |
| L | 电枢电感 | 5e-3 | H |
| Kt | 转矩常数 | 0.023 | N·m/A |
| Kb | 反电动势常数 | 0.023 | V·s/rad |
| J | 转动惯量 | 8e-5 | kg·m² |
| B | 粘性阻尼 | 1e-5 | N·m·s/rad |
| Tl | 负载转矩 | 0.02 | N·m |
拿到参数先别开 Simulink,先算两个时间常数。电气时间常数tau_e = L/R = 4.17 ms,机械时间常数取主导极点近似tau_m ≈ J*R/(Kt*Kb + R*B) = 9.6e-5 / 5.41e-4 ≈ 177 ms。两者差 42 倍,属于“有点刚性但 ode45 还能扛”的区间。
这个比值直接决定了后面所有工程决策:定步长该取多小、要不要换 ode15s、采样周期能不能设 1 ms、滤波器截止频率放哪。如果换成 L 取 0.5 H 的大电感电机,tau_e到 0.42 s,比值反过来小于 1,模型行为完全是另一回事。所以建模第一步不是拖模块,是把这个比值算出来写在纸上。
顺带算一下稳态工作点,避免参考速度设得离谱。给定 12 V、负载 0.02 N·m,稳态电流i = Tl/Kt ≈ 0.87 A,稳态转速omega = (12 - 1.2*0.87)/0.023 ≈ 476 rad/s。参考速度设 300 rad/s 是合理工况,设 10 rad/s 就属于自欺欺人——电压裕度还剩 97%,PID 怎么调都“完美”,换个工况立刻原形毕露。
2.2 MATLAB Function 模块:端口拆成标量,别传状态向量
原始写法用x(1)、x(2)取状态,作为教学示例没问题,搬进 Simulink 就要多接一个 Mux 和两个 Integrator 的初值对齐,很容易在向量维度上翻车。更省事的做法是把状态拆成两个独立端口,模块内部只做纯代数运算:
function [di, domega] = dc_motor_dynamics(i, omega, v, Tl, p) %#codegen % 输入输出全部为标量,直接对接两个 Integrator,无需 Mux % p: 参数结构体,来自模型工作区变量 P % P.R P.L P.Kt P.Kb P.J P.B di = (v - p.Kb*omega - p.R*i) / p.L; % 电枢回路方程 domega = (p.Kt*i - p.B*omega - Tl) / p.J; % 机械运动方程 end代码里没有积分、没有状态保持,只算导数,状态交给外面的 Integrator 积。这样拆的好处有三个:模块可以被代码生成直接吃下(%#codegen会做兼容性检查);两个 Integrator 的初值可以分别设成 0 和 0,不用凑向量;调试时探针直接戳在di和domega上,看得到电流环和机械环各自的动态。
参数用结构体传进去,是为了后面做参数扫描时能一次性替换整组数。在模型工作区或基础工作区里建一个P结构体:
P.R = 1.2; P.L = 5e-3; P.Kt = 0.023; P.Kb = 0.023; P.J = 8e-5; P.B = 1e-5;注意:结构体里的字段名大小写要和模块代码里完全一致。MATLAB Function 模块报“无法解析符号”时,九成是工作区变量名对不上,而不是代码写错。
v这个输入前面接 PID 输出,后面要过一级电压限幅。限幅不要塞在 PID 模块内部,单独放一个 Saturation 模块,饱和上下限用变量V_max、V_min表示,后面做扫描时能直接改。
2.3 求解器与步长:ode45、ode15s 和定步长怎么选
模型配置参数里的 Solver 选项,是这套仿真里第二个容易翻车的地方。按tau_m/tau_e ≈ 42的刚性比,可以这样分:
| 场景 | 求解器 | 步长 / 容差 | 说明 |
|---|---|---|---|
| 快速验证波形形状 | ode45(变步长) | RelTol 1e-3 | 默认选项,几十秒跑完 5 s 仿真 |
| 需要精确的超调量 | ode45 | RelTol 1e-5, AbsTol 1e-7 | 容差放宽会让超调量偏差 5% 以上 |
| 刚性比大于 100 | ode15s 或 ode23tb | 自动 | 变步长显式解法会被最小步长卡死 |
| 要生成 C 代码 / 上硬件 | ode4(定步长 RK4) | 1e-4 s | 步长必须小于 tau_e/10 |
定步长这条线要特别说一句:tau_e = 4.17 ms,如果图省事把步长设成1e-2,前向欧拉在一个电气时间常数内只走 0.4 步,电流环数值上直接不稳,波形表现是“电机转速越跑越大,最后飞到 1e6”。这不是控制器的问题,是积分器炸了。血泪经验是:定步长先按最小时间常数的十分之一起步,跑通了再往上放。
仿真时长也不用设太长。机械时间常数 177 ms,5 倍即 0.9 s 内基本调节完成,仿真 Stop time 设 2 s 足够看全过程。设 100 s 只会让你等得怀疑人生。
还有两个提速开关值得开:把“零 Crossing Detection”关掉能省 20%~30% 时间(波形上会丢一些开关细节,做控制环验证够用);把“Signal logging”只开需要的几路,别全模型默认记录。
3. PID 控制器从连续域落到 Simulink:限幅、抗饱和与初值给定
3.1 位置式与增量式:两种写法的数值差别
Simulink 自带的 PID Controller 模块够用,但如果你要自己写 MATLAB Function 版本(比如后面要做变参数或加前馈),就得先决定用位置式还是增量式。
位置式输出的是控制量本身:
function [u, integ] = pid_position(e, Kp, Ki, Kd, Ts, integ, e_prev, u_min, u_max) %#codegen % 位置式 PID,带钳位式抗饱和 integ_new = integ + e*Ts; % 先积分 u_raw = Kp*e + Ki*integ_new + Kd*(e - e_prev)/Ts; % 再算输出 % 钳位:输出已饱和且误差继续朝同方向推时,冻结积分 if (u_raw > u_max && e > 0) || (u_raw < u_min && e < 0) integ_new = integ; u_raw = Kp*e + Ki*integ_new + Kd*(e - e_prev)/Ts; end u = min(max(u_raw, u_min), u_max); integ = integ_new; end增量式输出的是控制量的变化量:
function du = pid_incremental(e, Kp, Ki, Kd, Ts, e1, e2) %#codegen % e1 = e[k-1], e2 = e[k-2],输出需要外部累加 du = Kp*(e - e1) + Ki*Ts*e + Kd*(e - 2*e1 + e2)/Ts; end差别在边界条件上。增量式天然不怕饱和——输出饱和时增量自然被截断,累加器在外部,不存在“积分项攒了一大堆”的问题;但累加器放在外部,一旦仿真中途改参数或复位,累加值要手动清。位置式结构直观,代价是必须显式写抗饱和逻辑。
对这套电机模型,我倾向位置式 + 钳位抗饱和。原因很实际:后面要做参数扫描,位置式的Kp/Ki/Kd三个量直接对应 Simulink PID 模块的三个参数框,改起来不用改结构。
Ts这个参数不能随手写。它是控制器的采样周期,和求解器步长是两回事。如果求解器用变步长 ode45,控制器又按固定Ts采样,就要在 PID 前面加一个 Zero-Order Hold,采样时间设Ts。Ts取多少?按闭环带宽的 10~20 倍,带宽按 20 rad/s 估,Ts取 1 ms 到 5 ms 都行。取 10 ms 就偏大了,离散化带来的相位滞后会明显吃掉相位裕度。
3.2 电枢电压限幅与积分饱和:一个必现的翻车点
不加限幅的仿真,起步瞬间误差是 300 rad/s,PID 输出能算出几百伏,电机“瞬间”到目标转速,波形漂亮得像理想系统。一加 ±12 V 限幅,问题全出来了:积分项在饱和期间继续累积,等转速冲过目标,积分项已经攒到很大,输出要反向饱和很久才能把积分拉回来,波形上就是一个大超调和一条长长的拖尾。
这就是积分饱和(windup),几乎每个第一次做这套仿真的人都会遇到。三种处理方式:
钳位法(clamping):上面代码里的做法,输出饱和且误差同向时冻结积分。实现简单,缺点是退出饱和有延迟。
反算法(back-calculation):把饱和前后输出之差反馈回积分器。
u_raw = Kp*e + Ki*integ + Kd*de; u = min(max(u_raw, u_min), u_max); integ = integ + e*Ts + (u - u_raw)/Kt_track; % Kt_track 一般取 sqrt(Ki/Kp)Kt_track取sqrt(Ki/Kp)或者积分时间的倒数,量纲上刚好抵消。这个方法的跟踪更平滑,代价是多一个需要整定的参数。
条件积分法:误差符号和输出饱和方向相反时才积分。实现最简单,效果介于两者之间。
Simulink 的 PID Controller 模块在“Limit output”勾选后会自动出现 Anti-windup method 选项,Clamping 和 Back-calculation 都能选。用内置模块时直接勾上就行,别自己再写一遍。
限幅值本身也要想清楚。电枢电压的物理上限是电源电压,12 V 系统就是 ±12;如果前面有 H 桥和 PWM,还要扣掉死区和管压降,实际给到 ±11 更保守。限幅值设太小,系统响应慢、稳态到不了目标;设太大等于没限,抗饱和也就白做了。
3.3 参数初值:临界比例度法在这台电机上不成立
教科书上的 Ziegler-Nichols 临界比例度法,步骤是“把 Ki、Kd 置零,Kp 加到系统等幅振荡,记下临界增益 Ku 和振荡周期 Tu”。这套方法对这套电机模型不适用。
原因在特征方程上。电压到转速的传递函数是
G(s) = Kt / [ (L*s + R)(J*s + B) + Kt*Kb ]二阶,无积分环节。加比例控制后闭环特征方程是s² + (R/L + B/J)s + (R*B + Kt*Kb + Kp*Kt)/(L*J) = 0。二次项和一次项系数都不含Kp,只有常数项随Kp增大。也就是说Kp从 0 加到无穷大,阻尼比从过阻尼一路降到 0 附近,但极点实部始终为负——系统永远不会等幅振荡,Ku 根本测不出来。
正确的做法有两条。一是用pidtune直接算:
s = tf('s'); R = 1.2; L = 5e-3; Kt = 0.023; Kb = 0.023; J = 8e-5; B = 1e-5; G = Kt / ((L*s + R)*(J*s + B) + Kt*Kb); opts = pidtuneOptions('DesignFocus','balanced'); C = pidtune(G, 'PID', opts); fprintf('Kp=%.4f Ki=%.4f Kd=%.6f\n', C.Kp, C.Ki, C.Kd);二是按降阶近似手算一组打底值。电气动态比机械快 40 多倍,可以把电流环当准稳态,传递函数退化成一阶惯性:
G_approx(s) ≈ K / (tau_m*s + 1), K = Kt/(R*B + Kt*Kb) ≈ 42.5 rad/s/V按内模法取闭环时间常数lambda = 20 ms(约 5 倍电气时间常数),得Kp = tau_m/(K*lambda) ≈ 0.21,Ki = 1/(K*lambda) ≈ 1.18。微分项对一阶系统没有必要,Kd先给 0。
这组Kp=0.21, Ki=1.18, Kd=0就是我在 Simulink 里填的第一版参数。跑出来通常是“有点慢但稳”,超调 5% 以内,再往上加Kp提响应、加一点Kd压超调。pidtune算出来的值一般比手算激进,Ki可能到 3 以上,直接填进去容易看到明显超调,需要把DesignFocus改成'reference-tracking'或者手动打七折。
4. 速度传感器建模:量化误差、可复现噪声与反馈滤波
4.1 三种测速方式的误差来源
反馈通道如果是理想的比例环节,整个仿真就变成了“PID 调一个一阶惯性”,说服力有限。真机上速度测量至少有三种实现,误差特性完全不同:
| 方式 | 原理 | 低速表现 | 高速表现 | 建模要点 |
|---|---|---|---|---|
| 直流测速发电机 | 输出电压与转速成正比 | 信噪比差,纹波占比大 | 线性度好 | 加换向纹波和温漂 |
| 增量编码器 M 法 | 固定时间内数脉冲个数 | 分辨率差,量化台阶明显 | 精度高 | 量化步长 2π/(Ts*ppr) |
| 增量编码器 T 法 | 固定脉冲数内测时间 | 精度高 | 计时器易溢出 | 误差随转速升高放大 |
| 霍尔传感器 | 每转输出固定个数脉冲 | 极差 | 一般 | 按极对数折算 |
用 M 法做量化建模最直观。分辨率为2π/(Ts*ppr),取Ts = 1 ms、ppr = 1000,量化步长是 6.28 rad/s。相对 300 rad/s 只有 2%,但相对 30 rad/s 就是 21%——低速段反馈几乎全是台阶。这就是为什么工业上低速用 T 法、高速用 M 法,或者干脆做 M/T 混合。
4.2 Band-Limited White Noise 的可重复噪声配置
Simulink 里的 Band-Limited White Noise 模块有三个参数:Noise power、Sample time、Seed。坑在于前两个的关系——输出序列的方差约等于 Noise power 除以 Sample time,不是直接等于 Noise power。默认 Noise power = 0.1、Sample time = 0.1,方差是 1;如果你把 Sample time 改成 1e-3 想模拟更细的噪声,方差会瞬间放大 100 倍,波形直接毛刺到没法看。
Sample time 必须设成传感器实际采样周期,不能设 0(0 表示连续,模块会按求解器步长生成,和定步长求解器配合时行为不可预期)。Seed 不固定的话,每次跑出来的曲线都不一样,调参时你根本分不清性能变化是参数带来的还是噪声带来的——这就是仿真界的玄学来源。
我一般不用内置噪声模块,直接在 MATLAB Function 里用固定种子的 RandStream,可控性更好:
function w_meas = speed_sensor(w_true, p) %#codegen % p.Ts 采样周期, p.ppr 每转脉冲数, p.noise_std 噪声标准差, p.seed 随机种子 % 1) M 法编码器量化 step = 2*pi/(p.Ts*p.ppr); counts = round(w_true/step); w_q = counts*step; % 2) 传输噪声,固定种子保证每次仿真曲线一致 persistent rs if isempty(rs) rs = RandStream('mt19937ar', 'Seed', p.seed); end w_meas = w_q + p.noise_std*randn(rs); endpersistent变量在每次仿真开始时不会自动清空,做参数扫描时必须手动clear speed_sensor,否则第二个用例拿到的噪声序列是接着第一个往下走的。这个问题极隐蔽,表现为“扫参结果的指标曲线不光滑”,排查半天以为是控制器问题。
noise_std取多少?按编码器手册给的角度误差折算,或者简单点:取量化步长的 0.3~0.5 倍。量化步长 6.28 rad/s 时,noise_std给 2~3 比较接近真实。
4.3 反馈通道加一阶低通:相位滞后换来的稳定性
加完噪声,很多人第一反应是把 PID 的Kd调小或者调大滤波。正确的做法是在反馈通道串一级一阶低通,截止频率按闭环带宽的 5~10 倍取。
离散一阶低通的实现:
function y = lpf1(x, fc, Ts) %#codegen persistent yk if isempty(yk), yk = 0; end a = exp(-2*pi*fc*Ts); % 零阶保持离散化系数 yk = a*yk + (1-a)*x; y = yk; enda的来源是H(s) = 1/(tau*s+1),tau = 1/(2*pi*fc),零阶保持离散化后a = exp(-Ts/tau)。fc和Ts一起决定滤波强度:Ts = 1 ms、fc = 50 Hz时a ≈ 0.73,相当于每步只信 27% 的新测量值。
fc不能一味往低放。一阶低通在fc处贡献 -45° 相位,如果fc只比闭环带宽高 2 倍,穿越频率附近的相位裕度会被吃掉 30° 以上,系统从“响应快”直接变成“振荡”。我一般先按fc = 10 * 闭环带宽试,跑出来超调变大就往回调Kp,而不是继续降fc。
滤波之后还有一个副作用:稳态时转速读数会有微小偏置(因为a不完全等于 1,直流增益是 1 没错,但阶跃响应有稳态误差吗?——一阶低通直流增益为 1,稳态无偏置,但暂态过程会拖慢反馈,等效于给反馈加了一个延迟环节)。这个延迟会限制你能达到的最短调节时间,属于物理约束,不是参数没调好。
5. 跑不通、波形不对的排查清单:五个高频翻车点
5.1 编译报代数环:反馈回路里少了一个状态
现象:模型编译时报 “Algebraic loop detected”,指向 PID 输出到电机再到 PID 的回路。
原因:回路里没有任何一个带状态的模块。如果电机用增益模块近似(准稳态i = (v - Kb*omega)/R直接代入转矩方程),PID 输出经过纯代数运算立刻回到 PID 输入,形成代数环。真实的电机有电感,di/dt经过 Integrator,回路里天然有状态,不会成环。
解决:两个方向。要么保留完整的二阶模型(推荐,本来就要建模电感动态);要么在反馈回路上串一个 Unit Delay 或一阶惯性打断环,代价是引入一个采样周期的延迟,仿真步长要相应调小。
5.2 波形指数发散:定步长比电气时间常数还大
现象:仿真跑到 0.3 s 左右,转速曲线开始指数上升,几秒后到 1e5 量级,Scope 自动缩放后看起来像一条竖直的线。
原因:定步长求解器(ode1/ode4)的步长超过了电气时间常数的稳定上限。前向欧拉对di/dt = (v - R*i)/L的稳定条件是Ts < 2*L/R = 2*tau_e,实际工程上要取tau_e/10以内。步长设 1e-2、tau_e = 4.17 ms时,数值积分必然发散。
解决:定步长改成1e-4;或者切回变步长 ode45,把 RelTol 收到 1e-4。改完先跑 5 s 看波形是否收敛,再开始调 PID。
5.3 脚本建模仿真报错:模块路径与参数名的版本差异
现象:用脚本add_block搭模型时,报 “Undefined function 'connect_lines'”,或者set_param报参数不存在。
原因:connect_lines不是 Simulink 的标准函数,标准的是add_line,且参数格式不同(需要指定端口如'PID/1'、'Motor/1')。set_param的参数名在不同 MATLAB 版本间会变,PID 模块的参数从老版的P、I、D到新版的对话框结构,跨版本脚本几乎必挂。
解决:脚本建模前先用get_param(blk, 'DialogParameters')打印出该模块当前版本支持的全部参数名,照着填。连线用add_line(model, 'Src/1', 'Dst/1', 'autorouting', 'on')。更稳的做法是手工搭一次模型存成.slx,脚本只负责改参数和跑仿真,不负责建结构——结构是低频操作,参数是高频操作,把高频的那部分脚本化收益最大。
5.4 优化脚本读不到数据:Scope 不是数据源
现象:遗传算法或扫参脚本跑完,每个个体的性能指标完全一样,或者直接报错说取不到SimulationData。
原因:get_param([model '/Speed Output Scope'], 'SimulationData')这个写法不成立。Scope 模块是可视化组件,不是数据记录组件,它没有SimulationData这个可读参数。仿真数据要么走logsout(信号记录),要么走 To Workspace 模块。
解决:把关键信号在信号线上右键“Log Selected Signals”,仿真后用out.logsout.get('omega').Values.Data取;或者在模型里放 To Workspace 模块,变量名设成omega_out,格式选Structure with time。改完再跑优化,指标才会随参数变化。
5.5 加噪之后稳态抖个不停:滤波器带宽和采样率不匹配
现象:稳态阶段转速在目标值上下 ±15 rad/s 反复抖,把噪声关掉就平滑了。
原因:三种可能叠加。噪声方差设太大(Noise power 和 Sample time 的关系搞反了);反馈低通截止频率高于奈奎斯特频率的一半,出现混叠;PID 的Kd项把高频噪声放大了几十倍。
解决:先确认fc < 0.4/Ts;再把noise_std降到量化步长的一半;最后检查Kd——微分项对噪声的放大倍数是Kd/Ts,Ts = 1 ms、Kd = 0.05时放大 50 倍,稳态抖动基本都来自这里。给微分项串一个N滤波器(Simulink PID 模块里的 Filter coefficient,取 100 左右),或者干脆把Kd压到 0,用 PI 控制这台电机已经够用。
6. 参数扫描与指标自动计算:把调参从手搓变成批处理
手动拖 PID 三个滑块、跑一次、看一眼 Scope,调十轮就到头了。真正能挖出参数边界的是批处理扫描:把Kp、Ki做成网格,每个组合自动跑一次仿真、自动算超调量和调节时间,最后画成热力图。
关键是别用set_param在循环里改模块参数——那会污染模型,而且没法并行。正确姿势是把 PID 参数改成工作区变量,用Simulink.SimulationInput打包:
mdl = 'dc_motor_speed_control'; Kp_list = 0.10:0.05:0.40; Ki_list = 0.50:0.50:3.00; R = zeros(numel(Kp_list), numel(Ki_list), 3); % 超调/调节时间/稳态误差 for i = 1:numel(Kp_list) for j = 1:numel(Ki_list) in = Simulink.SimulationInput(mdl); in = in.setVariable('Kp', Kp_list(i)); % 模型里 PID 填 Kp 而非常数 in = in.setVariable('Ki', Ki_list(j)); out = sim(in); t = out.logsout.get('omega').Values.Time; y = out.logsout.get('omega').Values.Data; R(i,j,:) = step_metrics(t, y, 300); % 参考速度 300 rad/s end endstep_metrics里算三个量:超调量按峰值减目标除以目标;调节时间按最后一次进入 ±2% 误差带的时间;稳态误差取末段 10% 数据的均值偏差。
function m = step_metrics(t, y, ref) %#codegen band = 0.02*ref; idx = find(abs(y - ref) > band, 1, 'last'); ts = t(min(idx+1, numel(t))); mp = (max(y) - ref)/ref*100; ess = mean(y(round(0.9*numel(y)):end)) - ref; m = [mp, ts, ess]; end这套跑完,你会看到一张很说明问题的图:Kp太小时调节时间被拖到 0.8 s 以上;Kp超过 0.35 后超调迅速破 20%;Ki在 1.0~1.5 区间是稳态误差和超调的平衡点。这些边界靠手调是看不出来的。想再快一步,把外层for换成parfor,配合Simulink.SimulationInput的并行支持,八个 worker 能把四小时的扫描压到半小时。
说个我自己踩过的坑:第一次做扫描时忘了在每轮开头清persistent变量,噪声序列一路累加,扫出来的指标曲线全是毛刺,还以为是控制器进入了混沌区,折腾了一下午。从那以后我每次跑批处理前,都强制在循环体第一行加一句clear speed_sensor lpf1,把带persistent状态的模块全清一遍再开始。这个习惯帮我省下的时间,比任何调参技巧都多。希望帮到你。
本文还有配套的精品资源,点击获取