智能小车作为嵌入式系统开发的经典练手项目,几乎每个电子相关专业的学生都会接触。但真正能把转向控制做精细的却不多见——要么转向角度不精确,要么响应延迟明显,要么遇到障碍物就乱转。这次我要分享的,正是用最基础的51单片机实现高精度转向控制的完整方案。
这个系统的核心诉求很明确:让小车能根据预设路径或传感器信号,快速、精准地完成转向动作。关键在于三个指标:
虽然STM32现在更流行,但我坚持使用STC89C52RC这颗老芯片有两个原因:
注意:如果选用12MHz晶振,记得在下载程序时勾选"6T模式",否则默认的12分频会让PWM频率太低导致电机抖动。
测试过三种常见方案后,我最终选择了L298N模块:
| 驱动芯片 | 最大电流 | 是否需要散热 | 价格 | 适用性 |
|---|---|---|---|---|
| L298N | 2A | 需要加散热片 | ¥8 | 最适合新手 |
| TB6612 | 1.2A | 无需散热 | ¥15 | 体积小但易烧 |
| L9110S | 0.8A | 无需散热 | ¥3 | 只适合微型电机 |
转向控制离不开环境感知,这套系统包含三类传感器:
转向本质是通过差速实现的,左右轮PWM占空比计算公式:
code复制左轮占空比 = 基础速度值 + 转向系数×角度偏差
右轮占空比 = 基础速度值 - 转向系数×角度偏差
在代码中要特别注意:
c复制// 51单片机PWM配置示例
TMOD |= 0x01; // 定时器0模式1
TH0 = 0xFC; // 1kHz PWM频率(12MHz晶振)
TL0 = 0x18;
ET0 = 1;
TR0 = 1;
void Timer0() interrupt 1 {
static unsigned char count = 0;
TH0 = 0xFC;
TL0 = 0x18;
if(count < left_duty) LEFT_MOTOR = 1;
else LEFT_MOTOR = 0;
// 右轮同理...
count = (count>=100)?0:(count+1);
}
单纯的比例控制会出现振荡,我采用了增量式PID算法:
code复制Δu(k) = Kp[e(k)-e(k-1)] + Ki*e(k) + Kd[e(k)-2e(k-1)+e(k-2)]
实际调试中发现几个关键点:
很多人在角度校准上栽跟头,我的经验是:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 转向时电机抖动 | PWM频率太低 | 调整定时器初值提高频率 |
| 角度持续偏大 | 机械结构重心偏移 | 调整电池位置配重 |
| 响应延迟明显 | 控制周期设置过长 | 将采样周期从100ms改为50ms |
| 遇到障碍物不转向 | 超声波模块盲区 | 调整安装角度或增加红外辅助 |
调试时发现电机启动会导致单片机复位,这是典型电源问题:
通过三个措施提升转向平顺性:
c复制filtered_output = 0.2*current_output + 0.8*last_output;
c复制void main() {
Init_PWM();
Init_Sensors();
while(1) {
Get_Sensor_Data();
Path_Planning();
PID_Calculate();
Motor_Output();
Delay_ms(50); // 控制周期
}
}
这套基础系统还可以进一步扩展:
实际测试中,这套系统在2m×2m的场地上能稳定完成8字形路径跟踪,平均转向误差仅3.2°,完全达到了设计目标。最让我意外的是,用51单片机做浮点运算居然也能达到50Hz的控制频率,证明老芯片只要用好了一样能打。