自动泊车系统听起来高大上,但拆解开来其实就是让小车自己完成"科目二考试"。我用TIM4C123G6HPM这块MCU做核心控制器时,发现它虽然引脚比STM32少些,但性能完全够用。整个系统可以分成三个关键部分:环境感知、决策控制和执行机构。
环境感知主要靠摄像头实现,这里我用的是OpenMV模块。它就像小车的眼睛,负责识别库位边线和停车标志。决策控制部分就是TIM4C123G6HPM的大脑,处理摄像头传回的数据,计算小车该往哪走。执行机构包括舵机和电机,舵机控制前轮转向,电机驱动后轮前进后退。
硬件连接其实很简单:
c复制// PWM引脚配置
PWM_Configure(PWM0, // 舵机控制
PWM1); // 电机控制
// UART配置
UART_Init(UART2, 115200); // OpenMV通信
实际调试时发现,TIM4C123G6HPM的PWM分辨率足够精确,转向控制很稳。但要注意电源管理,电机启动时的电流冲击可能会造成MCU复位,建议给电机驱动单独供电。
选硬件就像搭积木,每个部件都要严丝合缝。先说主控板,TIM4C123G6HPM是TI的M4内核MCU,80MHz主频完全够用。它的优势在于低功耗和丰富的外设,但要注意它的GPIO数量确实比STM32少,规划引脚时要精打细算。
小车底盘的选择很有讲究。题目要求前轮转向的四轮结构,我试过几种方案:
最终我选择了折中方案:铝合金底盘配合3D打印的转向机构。转向舵机建议选用20kg以上的金属齿轮舵机,实测SG90这类小舵机在频繁转向时容易烧毁。
供电系统是很多人容易忽视的部分。我的配置是:
提示:一定要给电机驱动加装大容量电解电容(我用了4700μF),能有效避免电压骤降导致的MCU复位。
循迹是自动泊车的基础,就像科目二要看准地上的线。传统红外对管在室外容易受干扰,所以我选择了摄像头方案。具体实现时,把OpenMV架在小车右侧,俯拍地面。
算法核心思路是:
代码实现关键点:
python复制# OpenMV端代码
import sensor, image, time
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)
while(True):
img = sensor.snapshot()
img.binary([(0, 64)]) # 自适应阈值二值化
line = img.get_regression([(255,255)], roi=(240,120,80,40))
if line: uart.write(str(line.x1()-280)+'\r\n') # 发送偏差值
TIM4C123G6HPM端用PID控制转向:
c复制float PID_Control(float err) {
static float last_err = 0, integral = 0;
float kp = 0.8, ki = 0.001, kd = 0.2;
integral += err;
float output = kp*err + ki*integral + kd*(err-last_err);
last_err = err;
return output;
}
实测发现,PID参数要根据车速调整。车速越快,kp应该越小,否则容易画龙。建议先用0.3m/s左右低速调试。
泊车逻辑就像给小车编写驾驶教科书,要分解每个动作步骤。以倒车入库为例,完整流程分为6个状态:
状态切换用有限状态机实现最清晰:
c复制enum ParkingState {
FOLLOW_LINE,
STOP_AT_MARK,
MOVE_FORWARD,
BACK_IN,
ADJUST,
FINISH
};
void ParkingFSM() {
static enum ParkingState state = FOLLOW_LINE;
switch(state) {
case FOLLOW_LINE:
if(detect_marker()) state = STOP_AT_MARK;
break;
case STOP_AT_MARK:
if(forward_distance > 30cm) state = MOVE_FORWARD;
break;
// 其他状态转换...
}
}
库角识别采用模板匹配法。先在OpenMV上截取标准库角图片作为模板,然后实时画面中进行匹配:
python复制template = image.Image("/template.pgm")
while(True):
img = sensor.snapshot()
r = img.find_template(template, 0.7)
if r: uart.write("MARK\r\n")
实际调试中发现,光照变化会影响识别率。后来我改用了特征点匹配+颜色过滤的双重验证,识别稳定性大幅提升。
调试自动泊车系统就像教新手开车,要有耐心。我总结了几条实用经验:
首先是分段调试法:
常见问题及解决方案:
识别库角不稳定
倒库位置偏差大
状态切换混乱
特别提醒:TIM4C123G6HPM的调试接口要用JTAG,比SWD稳定。我遇到过SWD连接不稳定的情况,后来改用JTAG就再没出过问题。
基础功能实现后,还可以做很多优化让系统更可靠。电源管理方面,我给MCU增加了看门狗和低电压检测:
c复制// 看门狗初始化
SYSCTL_RCGCWD_R |= 0x1; // 启用看门狗时钟
WATCHDOG0_LOAD_R = 0xFFFFFF; // 设置超时时间
WATCHDOG0_CTL_R |= 0x1; // 启用看门狗
运动控制方面,加入了加速度限制,避免急启急停:
c复制void set_motor_speed(float target) {
static float current = 0;
float max_delta = 0.02f; // 每周期最大变化量
if(target > current + max_delta) current += max_delta;
else if(target < current - max_delta) current -= max_delta;
else current = target;
PWM_SetDuty(MOTOR_PWM, current);
}
对于邻库有车的情况,我后来改进了识别算法:
这些优化让识别成功率从60%提升到了95%以上。虽然TIM4C123G6HPM跑不动大模型,但经过量化的微型CNN还是可以流畅运行的。
参加电赛最深的体会就是:硬件永远会出意想不到的问题。有一次比赛前夜,小车突然不能循迹了,排查半天发现是摄像头排线接触不良。现在我的工具箱里永远备着各种连接线和接插件。
TIM4C123G6HPM虽然资料不如STM32多,但TI提供的库函数很完善。我建议重点掌握这几个外设:
代码管理也很重要。建议采用模块化编程:
code复制/project
/hardware
motor.c
servo.c
sensor.c
/algorithm
pid.c
fsm.c
/image_processing
openmv_comm.c
main.c
这样不仅调试方便,团队协作也更高效。最后提醒大家,电赛题目一定要逐字阅读,我们曾经因为忽略了一个"连续"的要求,导致发挥失常。现在养成了用荧光笔标注关键要求的习惯。