有同学可能正在做为做飞思卡尔小车苦恼着,现在我就把当年我做小车的一些经验告诉大家吧,我是在2013年参加的第七届飞思卡尔竞赛,在下面这个跑到上小车能很轻松跑到3m以上。
现在已经研究生了,回想起当时做小车还是挺有感触的,小车包括三大部分,机械、硬件、软件。
首先,机械部分是小车能否跑到3m以上很关键的一部分,小车的机械部分的改进需要参考赛车的一些设计,比如要尽量贴地,要向前倾,轮距要合适,舵机转幅要大等等,小车一定要做的精致,能够做小的地方就要做小,轮子要用使用过一段时间的轮子,摄像头的前探距离要够长,范围要广(使用广角镜),用采集卡采集的画面要清晰等等。
其次,小车的硬件设计也是很关键的部分,如果同学们自己不能设计核心板可以购买现成的核心板,但是底板要尽量小,散热要好(散热主要跟程序有关),布线要合理,尽量不用跳线,不用杜邦线,要保证小车不会因为硬件的问题而烧CPU,发热导致电路板保护,电机保护。
最后,程序显而易见是重中之重,摄像头的采集程序要做到精简,因为我们的摄像头采集很多是通过中断的方式采集,如果中断服务程序过长的话就会一直进入中断,影响小车判断终点等,摄像头的采集我这儿用的是硬件二值化的方式:
/*********************************************************
* ISR_Sample_Up
* 上升沿(即白到黑的跳变)采集中断的中断服务程序
**************************************/
ISR_Sample_Up()
{
INT16U cnt_up_tmp ;
cnt_up_tmp = READ_Camera_Timer();
CLR_UpInt(); /*清中断标志*/
if(Flag_Down - Flag_Up == 1)
{
v_point_up[Line_Save][Flag_Up] = cnt_up_tmp;
Flag_Up ++;
}
}
/*********************************************************
* ISR_Sample_Down
* 下降沿(即黑到白的跳变)采集中断的中断服务程序
**************************************/
ISR_Sample_Down()
{
INT16U cnt_down_tmp;
cnt_down_tmp = READ_Camera_Timer();
CLR_DownInt(); /*清中断标志*/
if(Flag_Down - Flag_Up == 0)
{
v_point_down[Line_Save][Flag_Down] = cnt_down_tmp;
Flag_Down ++;
}
}
/*********************************************************
* ISR_Sample_Point
* 上升/下降沿采集中断的中断服务程序
(当CPU的外部中断口较少时,只能使用一个中断同时采集上升下降沿)
**************************************/
ISR_Sample_Point()
{
INT16U cnt_tmp;
cnt_tmp = READ_Camera_Timer();
CLR_PointInt(); /*清中断标志*/
NEG_PointInt(); /*对触发方式取反*/
if(Flag_Down - Flag_Up == 0)
{
v_point_down[Line_Save][Flag_Down] = cnt_tmp;
Flag_Down ++;
}
else
{
v_point_up[Line_Save][Flag_Up] = cnt_tmp;
Flag_Up ++;
}
}
/*********************************************************
* _INT_Field
* 场中断的中断服务程序
**************************************/
ISR_Field()
{
CLR_FieldInt(); /*清中断标志*/
EN_LineInt(); /*使能行中断*/
DIS_FieldInt(); /*关闭场中断*/
NEG_FieldInt(); /*调整场中断的触发条件*/
CntField++; /*场计数变量加1*/
}
/*********************************************************
* ISR_Line
* 行中断的中断服务程序
(行中断之后要保证处理时间小于行消隐区的时间)
**************************************/
ISR_Line()
{
CLR_LineInt(); /*清中断标志*/
START_Camera_Timer(); /*开启定时器*/
/*注意定时器的初始化必须放在一开始,从而保证定时起始时刻相对于行中断到来时刻的时间差为定值*/
DIS_PointInt(); /*关上升/下降沿中断*/
LineCCD++;
if(LineCCD == LineCCD_End) /***本场采样结束***/
{
LineCCD = 0;
PointNum[Line_Save++] = (INT8U)Flag_Down; /*记录最后一行的边沿数*/
DIS_LineInt(); /*关行中断*/
CLR_FieldInt(); /*清场中断标志*/
EN_FieldInt(); /*使能场中断*/
}
else if(LineCCD > LineCCD_Start) /***正常采样行***/
{
if(Flag_Pick != 0)
{
PointNum[Line_Save++] = (INT8U)Flag_Down; /*记录上一行的边沿数*/
Flag_Pick = 0;
}
if(Ptr_LineCfg[Line_Save] == LineCCD) /*查表判定是否需要采样*/
{
Flag_Down = 0;
Flag_Up = 0;
Flag_Pick = 1;
#if CAR_PointIntMode == 1
Set_PointInt_Down();
#endif
CLR_PointInt(); /*清上升(下降)沿中断标志*/
EN_PointInt(); /*开上升/下降沿中断*/
}
}
else if(LineCCD == LineCCD_Start) /***一场的开始***/
{
#if EN_Check_TimeOut != 0
if(Line_Process != NUM_Line)
{ /*处理超时判定*/
TimeOutFlag = 1;
Cnt_TimeOut++;
}
#endif
Line_Process = 0;
Line_Save = 0;
Flag_Down = 0;
Flag_Up = 0;
Flag_Pick = 1;
#if CAR_PointIntMode == 1
Set_PointInt_Down();
#endif
CLR_PointInt(); /*清上升(下降)沿中断标志*/
EN_PointInt(); /*开上升/下降沿中断*/
}
}
将摄像头采集到的数据处理之后就能够知道小车在跑到上的位置了,接下来要做的是将小车的位置对应到小车舵机的转向上去,这里不同的采集方案对应不同的舵机控制,但是小车舵机的控制一定要考虑并处理好盲区的问题,也就是小车摄像头照在跑到之外舵机的转向也必须正确!!如果能够正确的转向(建议转向的幅度跟小车偏差的位置成线性变化),那么就可以增加策略并且控制速度了,这里提供增量式PID算法:
/**************************内部函数**************************/
#if EN_ClosedLoop != 0
/*********************************************************
* Speed_PID
* 增量式速度PID控制
**************************************/
static void Speed_PID(void)
{
INT32S pwmdelta;
/*PID运算*/
pwmdelta = (KP_Speed+KI_Speed+KD_Speed)*((INT32S)SpeedErr);
pwmdelta -= (KP_Speed+2*KD_Speed)*((INT32S)His_SpeedErr);
pwmdelta += KD_Speed*((INT32S)His2_SpeedErr);
/*设定电机PWM*/
SetMotorPWM(MotorPWM+(INT16S)(pwmdelta/20L));
}
#endif
至此,你可以完成一辆小车的基本功能了,在这个环境下你要让你的小车达到2.5m/s以上,接下来,你可以开发一个上位机程序通过外接蓝牙或者wifi模块采集小车实时数据,包括摄像头采集到的图像和小车速度方向数据,通过对数据的分析模拟可以进一步改进小车的速度。