循迹小车低速一顿一顿,我靠串口打印揪出了干扰源
下午调试一辆 PID 循迹小车,电机在低速段明显一顿一顿,速度曲线像锯齿一样跳。PID 参数调了半天没改善,反而越调越乱。直觉告诉我这不是算法问题,而是硬件层面的干扰。
硬件清单
· 主控:Arduino UNO R3
· 驱动器:艾思控AQMD2403BLS-M(适配 12V-18W / 24V-50W,电流6A/3A,能耗制动3A,尺寸 45×45×18mm 裸板)
· 电机:12V 带编码器直流减速电机(60 线 AB 相)
· 电源:12V 3A 锂电池组
· 传感器:5 路红外循迹模块(TCRT5000)
· 其他:杜邦线若干、面包板
接线说明
· AQMD2403BLS-M 的 PWM 输入接 UNO D3(硬件 PWM 引脚),DIR 接 D4,GND 与 UNO 共地。
· 电机编码器 A/B 相分别接 UNO D2/D3(外部中断引脚),注意 D3 已被 PWM 占用,这里需要换到D18/D19(即 A0/A1 对应的中断引脚,UNO 只有 D2/D3 有中断,所以实际接D2/D3,PWM 改到D5)。
· 红外循迹模块输出接A0~A4,VCC/GND 从 UNO 5V 引出。
· 电机电源和逻辑电源共用 12V 电池,驱动器 VIN 接电池正极,GND 接电池负极,UNO 通过 Vin 引脚从同一电池取电。
【配图建议:接线拓扑图,标注功率回路与信号回路的走线路径】
现象描述
· 占空比低于 20% 时,电机启动困难,偶尔"咔哒"一声才转起来。
· 匀速运行时,串口打印的编码器计数值忽大忽小,速度反馈跳变明显。
· 红外循迹读数在电机启停瞬间出现毛刺,偶尔误判黑线位置。
· 用手轻触驱动器外壳,能感觉到轻微的麻手感(感应电)。
排查过程
第一步,怀疑 PID 参数没调好。把 Kp 从 2.0 降到0.5,Ki 清零,Kd 从 0.1 升到0.3,现象依旧,低速抖动没有改善。排除算法问题。
第二步,怀疑编码器接线松动或信号线太长。缩短编码器线到5cm,用屏蔽线重接,抖动减轻但没消除。排除纯接线问题。
第三步,用万用表测编码器 A 相波形,发现电机运行时信号线上叠加了大约 200~300mV 的高频噪声。把示波器探头换到红外模块的输出引脚,同样看到电机换相时的尖峰脉冲。此时基本锁定:功率回路的噪声耦合到了信号线上。
根因分析
- 共地走线不合理:电机大电流回路与编码器/传感器信号线在面包板上共用了一段 GND 走线,电机换相时的 di/dt 在 GND 阻抗上产生压降,直接叠加到信号地参考上。
- 编码器线与电机线平行走线:两者并排捆扎了 15cm 左右,电机线上的高频噪声通过分布电容耦合到编码器信号线。
- AQMD2403BLS-M 的 PWM 频率较高:该驱动器默认 PWM 频率约 20kHz,快速开关产生的 dv/dt 通过寄生电容辐射到邻近的模拟信号线,红外模块的模拟输出尤其敏感。
解决过程
硬件上做了三处改动:
- 把编码器线换成双绞屏蔽线,屏蔽层单端接驱动器 GND。
- 红外模块的每路输出加一个 100nF 电容到GND,做简单的 RC 低通滤波。
- 重新布线:电机功率线走底板一侧,信号线走另一侧,两者交叉时垂直跨越,不平行走线。
软件上,用串口打印代替示波器,实时观察编码器速度和红外读数,确认改善效果:
// PID 循迹小车 - 串口调试版
volatile longencoderCount = 0;
unsigned long lastTime = 0;
float lastSpeed = 0;
void setup() {
Serial.begin(115200);
pinMode(2, INPUT_PULLUP); // 编码器 A 相
pinMode(3, INPUT_PULLUP); // 编码器 B 相
attachInterrupt(digitalPinToInterrupt(2), onEncoder, CHANGE);
pinMode(5, OUTPUT); // PWM 输出到驱动器
pinMode(4, OUTPUT); // DIR
lastTime = millis();
}
void loop() {
unsigned long now = millis();
if (now - lastTime >= 50) { // 每 50ms 计算一次速度
noInterrupts();
long count = encoderCount;
encoderCount = 0;
interrupts();
float speed = count / (50.0 / 1000.0); // 计数/秒
// 简单移动平均滤波,平滑速度反馈
lastSpeed = 0.7 * lastSpeed + 0.3 * speed;
// 串口打印:时间戳 | 原始计数 | 滤波后速度
Serial.print(now);
Serial.print(",");
Serial.print(count);
Serial.print(",");
Serial.println(lastSpeed, 1);
lastTime = now;
}
// PID 控制逻辑省略...
}
void onEncoder() {
encoderCount++;
}
验证结果
改造后低速占空比 10% 也能平稳启动,不再有"咔哒"声。串口绘图器里速度曲线从锯齿状变成了平滑的波浪线,红外读数在电机启停时也不再跳变。实测下来,低速段的速度标准差从大约 ±15 计数降到了 ±3 计数以内。
踩坑小结
- 信号线与功率线必须分开走,平行走线超过 5cm 就要警惕耦合噪声。
- 编码器线用双绞屏蔽线,屏蔽层单端接地,比裸杜邦线抗干扰能力强很多。
- 模拟信号输出加 RC 滤波,100nF 电容并联到 GND,成本几乎为零但效果明显。
- 没有示波器就用串口打印,Arduino 的 Serial Plotter 足够观察趋势变化,排查干扰问题够用。
- 共地不是简单地连在一起就行,大电流回路的 GND 压降会污染整个参考地,星型接地或单点接地更可靠。
结尾
这次排查下来,硬件布线的细节比 PID 参数更影响低速性能。大家做小车时有没有遇到过类似的"玄学抖动",最后是怎么解决的?




