别再只用TT马达了!手把手教你用STM32+双电机+编码器打造一台能测速的智能小车
从玩具到竞赛级:STM32智能小车电机选型与编码器测速实战
第一次用TT马达组装智能小车时,那种看到轮子转动的兴奋感至今难忘。但当我带着作品参加高校智能车竞赛,才发现玩具级电机在精准控制和持续负载下的力不从心——速度波动大、响应延迟、无法反馈实时转速。这促使我深入研究带编码器的直流电机方案,本文将分享如何用STM32实现工业级电机控制的技术跃迁。
1. 电机选型:从TT马达到编码器电机的性能跨越
许多创客的第一个智能小车项目都从橙色外壳的TT马达开始,这种售价不足10元的直流电机因价格低廉成为入门首选。但当我们开始实现循迹、避障或竞速等需要精确控制的应用时,TT马达的三大缺陷就会显现:
- 无速度反馈 :只能通过PWM占空比估算转速,实际速度受负载影响波动可达±30%
- 扭矩不足 :130电机在6V电压下扭矩仅0.3kg·cm,爬坡或加速时易出现失速
- 寿命短暂 :碳刷结构在连续工作2-3小时后性能明显下降
相比之下,带霍尔编码器的直流电机(如JGA25-370)在同等尺寸下可实现:
| 参数 | TT马达 | 编码器电机 | 提升幅度 |
|---|---|---|---|
| 扭矩 | 0.3kg·cm | 3.2kg·cm | 10.6倍 |
| 编码器分辨率 | 无 | 11PPR×64 | ∞ |
| 最大转速 | 200RPM | 450RPM | 2.25倍 |
| 持续工作时间 | 2-3小时 | 50小时+ | 25倍 |
实际测试显示:在5cm爬坡测试中,TT马达需要100%占空比才能勉强登顶,而编码器电机在60%占空比下即可稳定运行,且通过PID控制可将速度误差控制在±2RPM内。
2. 硬件架构:STM32与双电机驱动方案设计
要实现真正的闭环控制,需要构建包含速度检测、中央处理和功率驱动的完整硬件链路。以下是基于STM32F407的推荐配置:
// 电机驱动核心组件清单
1. STM32F407ZGT6 // 带高级定时器,适合编码器接口
2. L298N双H桥模块 // 峰值电流2A,支持PWM调速
3. JGA25-370电机 // 内置霍尔编码器(11PPR)
4. 18650电池组 // 7.4V电压,2000mAh容量
5. 铝合金底盘 // 尺寸20x15cm,带电机安装孔
关键电路连接要点 :
- 将编码器A/B相分别接入TIM2_CH1/TIM2_CH2(支持正交解码)
- 电机驱动IN1/IN2接PA6/PA7(普通GPIO),ENA接PB0(PWM输出)
- 在VS(驱动电压)和VSS(逻辑电压)间跨接100uF电容滤波

注:实际布线时应将电机电源与MCU电源地线在一点共地,避免大电流干扰。
3. 编码器数据采集:四倍频与速度计算实战
STM32的编码器接口模式可将霍尔信号转换为精确的转速数据。以11PPR编码器为例,配合四倍频技术可实现每转44个计数脉冲。配置步骤如下:
// TIM2编码器模式初始化
void Encoder_Init(void) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_Period = 65535; // 16位最大值
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12,
TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 6; // 设置输入滤波器
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
速度计算算法 :
- 每50ms读取一次计数器值CNT
- 计算ΔCNT = 当前CNT - 上次CNT
- 转速RPM = (ΔCNT × 60 × 1000) / (44 × 采样间隔ms)
- 重置CNT并启动下次采样
实测发现,在电机加速阶段,原始数据会出现毛刺。通过滑动窗口滤波可有效平滑:
# Python实现的滑动平均滤波
class MovingAverage:
def __init__(self, window_size=5):
self.window = []
self.size = window_size
def update(self, value):
self.window.append(value)
if len(self.window) > self.size:
self.window.pop(0)
return sum(self.window)/len(self.window)
4. PID控制实现:从理论到参数整定
有了精准的速度反馈后,便可实现闭环PID控制。离散化PID公式为:
u(k) = Kp*e(k) + Ki*∑e(j) + Kd*(e(k)-e(k-1))
在STM32上实现的简化代码:
typedef struct {
float Kp, Ki, Kd;
float integral;
float prev_error;
} PIDController;
float PID_Update(PIDController* pid, float setpoint, float measurement) {
float error = setpoint - measurement;
pid->integral += error;
if(pid->integral > 1000) pid->integral = 1000;
if(pid->integral < -1000) pid->integral = -1000;
float derivative = error - pid->prev_error;
pid->prev_error = error;
return pid->Kp * error +
pid->Ki * pid->integral +
pid->Kd * derivative;
}
参数整定经验 :
- 先设Ki=Kd=0,逐渐增大Kp直到出现等幅振荡
- 取振荡周期Tu和增益Ku,按Ziegler-Nichols法计算:
- Kp = 0.6*Ku
- Ki = 2*Kp/Tu
- Kd = Kp*Tu/8
- 微调时遵循"先稳后快"原则:
- 出现超调增大Kd
- 稳态误差大增大Ki
- 响应慢增大Kp
实测某小车的最佳参数为:Kp=12.5, Ki=0.8, Kd=0.3,速度阶跃响应曲线显示:
- 上升时间:0.3s
- 超调量:<5%
- 稳态误差:±1RPM
5. 系统集成:多传感器融合与无线控制
完成基础速度控制后,可扩展更多竞赛级功能:
循迹方案对比 :
- 红外对管:成本低但易受环境光干扰
- 灰度摄像头:需图像处理算法(OpenMV)
- 激光雷达:精度高但价格昂贵
推荐性价比方案:TCRT5000红外阵列+STM32 ADC采样:
// 五路红外循迹采样代码
void LineSensor_Read(uint16_t* values) {
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_84Cycles);
for(int i=0; i<5; i++) {
GPIO_WriteBit(GPIOA, GPIO_Pin_0<<i, Bit_SET); // 依次选通
Delay_us(10);
ADC_SoftwareStartConv(ADC1);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
values[i] = ADC_GetConversionValue(ADC1);
GPIO_WriteBit(GPIOA, GPIO_Pin_0<<i, Bit_RESET);
}
}
WiFi控制实现 :
- 使用ESP8266模块的AT指令模式
- 配置为TCP服务器(端口8080)
- STM32通过USART接收控制指令
典型通信协议设计:
[开始符][长度][命令][数据][校验和]
0xAA 0x05 0x01 0x64 0xCE
(表示设置目标速度为100RPM)
6. 性能优化:从实验室到赛道的实战技巧
在真实比赛中,我们发现了几个教科书上不会提及的细节问题:
-
电源干扰 :电机启停导致STM32复位
- 解决方案:在电机电源线加磁环,MCU电源加220uF钽电容
-
编码器丢脉冲 :高速时出现计数不准
- 优化措施:将GPIO速度设置为High,滤波器值设为8
-
轮胎打滑 :影响速度测量精度
- 应对方法:在轮胎内侧贴3M防滑胶带,增加摩擦力
一个有趣的发现:当小车从木地板切换到沥青路面时,最优PID参数需要重新调整。这是因为不同路面的滚动阻力系数变化导致:
| 路面类型 | 摩擦系数μ | 推荐Kp调整幅度 |
|---|---|---|
| 木地板 | 0.3 | +0% |
| 沥青 | 0.5 | -15% |
| 地毯 | 0.7 | -30% |
最后分享一个调试PID的实用技巧——在STM32的DAC输出端接示波器,可以同时观察:
- 通道1:目标速度(方波)
- 通道2:实际速度(滤波后)
- 通道3:PWM输出
这种可视化调试方法比单纯看串口数据效率提升至少3倍。
更多推荐



所有评论(0)