1. 从开环到闭环:为什么需要电机驱动控制?
当你第一次让物流小车的轮子转起来时,那种成就感肯定很强烈。但很快就会发现,单纯给电机PWM信号就像骑没有刹车的自行车——速度完全靠感觉,遇到上坡就变慢,下坡又失控。这就是开环控制的局限性。
我在去年指导参赛队时就遇到过这种情况。学生们给电机固定占空比的PWM,小车在空载时跑得挺稳,但装上500g配重后速度直接降了40%。更麻烦的是,不同电池电压下速度波动能达到±30%。这时候就需要引入闭环控制——用编码器当"速度计",让系统自动调节PWM维持设定转速。
闭环系统的核心是三个部件:
- 执行器:电机驱动板(如TB6612、DRV8833)
- 传感器:光电编码器或霍尔编码器
- 控制器:Arduino实现的PID算法
实测表明,加入速度闭环后,相同负载下的速度波动能控制在±2%以内。这为后续的路径跟踪、精确定位打下了基础。
2. 硬件搭建:编码器安装与信号处理
2.1 编码器选型要点
常见的有两种编码器方案:
- 霍尔编码器:成本低(约15元/个),精度通常为13PPR(每转脉冲数)
- 光电编码器:精度高(100-500PPR),但价格贵3-5倍
对于物流小车,我推荐用霍尔编码器。去年我们用某宝20元的JGA25-370电机(自带霍尔编码器),实测在3m/s速度下完全够用。安装时要注意:
- 编码器线建议用双绞线,防止电机干扰
- 电源线(红黑)与信号线(绿白)分开走线
- 电机外壳需要接地
2.2 信号采集电路
编码器输出是正交脉冲信号,需要用中断引脚捕获。以Arduino Mega为例:
// 接线定义 #define ENCODER_L_A 2 // D2接左电机A相 #define ENCODER_L_B 3 // D3接左电机B相 #define ENCODER_R_A 18 // D18接右电机A相 #define ENCODER_R_B 19 // D19接右电机B相 volatile long encoder_L = 0; volatile long encoder_R = 0; void setup() { pinMode(ENCODER_L_A, INPUT_PULLUP); pinMode(ENCODER_L_B, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(ENCODER_L_A), count_L, CHANGE); // 右电机同理 }3. 增量式PID算法实现
3.1 算法原理拆解
PID控制就像骑自行车时的三个本能反应:
- 比例(P):当前速度比目标慢就多蹬几圈(误差越大,调节越猛)
- 积分(I):发现持续上坡就保持用力(消除稳态误差)
- 微分(D):看到前方下坡提前收力(抑制超调)
增量式PID的特点是只计算输出变化量,代码更安全:
float Kp=0.8, Ki=0.05, Kd=0.1; // 需要调试的参数 float last_error = 0, prev_error = 0; int PID_Update(float target, float current) { float error = target - current; float delta = Kp*(error-last_error) + Ki*error + Kd*(error-2*last_error+prev_error); prev_error = last_error; last_error = error; return delta; // 返回PWM增量 }3.2 参数整定技巧
调试PID有个口诀:"先比例,后积分,最后加微分"。具体步骤:
- 将Ki和Kd设为0,逐渐增大Kp直到出现小幅振荡
- 取此时Kp值的50%作为初始值
- 增加Ki直到静差消除(但别让系统变慢)
- 最后加Kd抑制超调
实测发现,物流小车通常适合的参数范围:
- Kp: 0.5~2.0
- Ki: 0.01~0.1
- Kd: 0.1~0.5
4. 闭环系统集成与测试
4.1 控制周期选择
通过示波器抓取发现:
- 周期>20ms时,速度波动明显
- 周期<5ms时,Arduino处理不过来
- 10ms是最佳平衡点,既能及时响应又不会过载
定时中断配置示例:
#include <TimerOne.h> void setup() { Timer1.initialize(10000); // 10ms周期 Timer1.attachInterrupt(controlLoop); } void controlLoop() { // 在这里执行速度计算和PID更新 }4.2 抗干扰设计
比赛中常遇到的三个坑:
- 电机干扰:在电源端加1000uF电容,编码器线加磁环
- 脉冲丢失:在中断服务函数里添加消抖逻辑
- 电池衰减:实时监测电压,动态补偿PWM最大值
去年有个队伍在决赛时因为裁判台电磁干扰导致编码器乱跳,后来我们在信号线上串了100Ω电阻解决问题。
5. 进阶优化方向
5.1 速度前馈控制
像汽车定速巡航那样,提前根据路况调节:
float feedforward = 0; if (on_slope) feedforward = 50; // 上坡提前加大PWM void updatePWM() { pwm = PID_Update(target, current) + feedforward; }5.2 动态参数调整
不同速度段用不同参数:
float getKp(float speed) { if (speed < 0.5) return 1.2; // 低速用大Kp else return 0.6; // 高速减小Kp }这些技巧让我们在去年国赛的8字绕桩环节,实现了±1cm的轨迹跟踪精度。现在你的小车应该已经能稳稳地跑直线了,下一阶段我们会把重点放在多传感器融合与路径规划上。