本系统的功能为通过传感器对小车行驶的周边环境进行探测,遇到障碍物要进行有效的避障处理,并进行相应的危险状况播报,同时还可以根据预定的进行寻迹行驶等。
系统总体结构框图如下:
超声波模块采集小车前面障碍物的距离信息;红外传感器采集小车前部下方预设轨迹的变化信息。STM32主控芯片采集红外传感器及超声波传感器输出的信号,对它们的信息进行融合处理,经过数据分析之后发出相应控制指令传给L298N驱动模块及语音模块,对电机作出相应的驱动处理,对危险信息进行播报,实现对小车行驶的自动控制。
1.电机驱动模块电路设计
本次设计中的电机驱动芯片选用了L298N,它是一款接受高电压的电机驱动器,直流电机和步进电机都可以驱动。一片驱动芯片可同时控制两个直流减速电机做不同动作,在6V到46V的电压范围内,提供2安培的电流,并且具有过热自断和反馈检测功能。L298N可对电机进行直接控制,通过主控芯片的I/O输入对其控制电平进行设定,就可为电机进行正转反转驱动,操作简单、稳定性好,可以满足直流电机的大电流驱动条件。
2.超声波模块电路设计
根据智能小车控制器的避障需求,环境探测传感器应具有精确的探测功能,以获得周边环境的完整信息,同时还要为小车运动提供实时的信息。具有处理速度快,低功耗,容易使用等优点,且不受到外界环境的影响。但也有一些局限:检测角度较小,方向性较差,所以单个超声波模块的准确性并不理想,测量范围存在盲点。在实际开发应用中,会采取一些措施进行补偿处理,然后利用信息汇总技术对准确度进行提高。
超声波距离测量原理非常简单,一般采用回波时间法,即检测超声波往返所测距离的时间,当发射器发出一个短脉冲时,定时器启动;当接收器接收到返回脉冲时,定时器立即停止。此时记录的时间值为D = CT / 2,其中D为超声波传感器与测量对象之间的距离,C为介质中声波的传播速度(C = 331.4+t273 / 1m / s,t是摄氏温度),T是超声波发射回波的时间间隔。理论上,超声波在正常空气中传播速度随着介质温度的升高而有所加快,温度提高了一度,速度提高0.6 m/s左右。原理结构如图3.12所示。
超声波传感器主要由三部分组成:控制部分,总线部分,超声波发射接收部分。主控芯片通过I/O口发送信号,通过总线发送到两个发生电路中,控制着两个超声波的发射,然后再由两个信号接收电路对接收超声波信号进行放大,最后通过总线传送到主控芯片的输入端口,然后根据发射接收时间差T,计算出传感器与障碍物之间的距离,最后根据距离对小车的行驶安全性进行判断,并做出相应动作。
3.语音模块电路设计
本设计中采用的是ISD1820语音模块,它是美国ISD公司于2001年推出的一款单芯片8至20秒单段语音录放电路模块,基本结构与之前的ISD1110和ISD1420原理几乎相同,都是采用了CMOS技术,配置振荡器、滤波器、增益控制、话筒前置放大、扬声驱动及FLASH阵列。
4.红外模块电路设计
本次选用的红外对管模块适应环境光的能力很强,具有一对发射接收管,发射管发射一定频率的红外线,当检测到黑线时,不能反射回接收管,比较电路处理完后,绿色灯亮,信号输出接口不能输出数字信号。 可以通过电位器的旋钮调节灵敏度,有效检测距离范围为2到30厘米,正常工作电压为3.3到5V。具有抗干扰,易安装使用等特点,广泛应用于自动避障循迹。
红外模块电路原理如图所示,图中10K限流电阻,不同性能的限流电阻决定了红外发射功率,限流电阻越小,发射功率越大。当光反射回来三极管导通,LM393两个输入端,同相输入端用“+”表示,反相输入端用“-”表示。用于比较两个电压,任一个输入端加一个固定电压做参考电压,即阈值电平。另一端加上比较电压。当反相输入电压低于同相输入电压时,输出截止。否则输出端饱和,输出接地。只要LM393的两个输入电压差大于10mv,就可以确保输出从现状态可靠转换到另一状态。使用比较器就可以不用AD转换电路,经过LM393后在主控芯片控制端口产生高电平,从而完成检测的目的。模块的灵敏度可以通过变阻器VR1进行调整。
5.显示模块电路设计
LCD1602模块的命令操作端有RS、RW和EN,单片机的P2^5、P2^6、P2^7脚分别与之相连。数据端口DB0~DB7分别接在单片机的P0^0~P0^7。为了保持LCD1602液晶具有较高的亮度,一般电路设计中都会将VL端串联一个2K的电阻接地。
6.主程序设计
开始先是对单片机的初始化,其中包括对外部中断初始化和液晶的初始化。然后调用超声波测距子程序,判断前方300mm处是否存在障碍物,如果存在进行避障处理,如果不存在则进行红外对管检测,并做出相应动作。
7.电机驱动程序设计
开始通过超声波模块和红外模块的检测,判断中断请求,如果没有中断请求则保持原状态,如果有中断请求则调控PWM进行避障或者循迹运动。通过P1^3电平检测,把它赋给temp,根据P1低四位电平,给出相应的驱动电平送到L298N,从而控制小车的直走停止,左右转等动作。
8.超声波避障程序设计
超声波避障程序的设计思想主要是依据超声波测距原理。首先,单片机给超声波模块Trig端发送一个高电平且持续20us,再给Trig端发送一个低电平,启动超声波模块,随即超声波模块会发送8个40KHZ的方波,等待信号返回,如果有信号返回则超声波模块的Echo端输出一个高电平,接收高电平的时间就是超声波从发射到接收的时间,测试距离就等于(接收高电平时间*340)/ 2,单位为m。计算出障碍物和智能小车的距离,取前方多个方向的值,然后进行多次采样,以此减小数据误差,最后进行数据处理,通过软件算法判断最优路线,智能小车向目标方向行驶。
9.语音模块程序设计
它的工作状态和检测障碍存在信号是同步的,当检测到前方存在障碍物,语音模块就会进行障碍信息播报。
10.红外循迹程序设计
首先对小车状态进行检测,如在轨迹上,则调用直走子程序,即两电机都正转;如偏向轨迹左边,则调用右转子程序,即左电机正转右电机反转;如偏向轨迹右边,调用左转子程序,左电机反转右电机正转;如到轨迹终点,则调用停止子程序,即两电机都不转。
11.显示模块程序设计
LCD1602液晶显示程序的设计流程为先调用定义字符库,然后将DDRAM地址设置在第一行显示位置上,再根据系统数据对显示数据首地址及程序循环量进行设置,在循环显示程序中,要不断地提取相关字符代码直至第一行数据显示任务完成,同理,第二行数据显示任务与第一行完成过程是一样的,当两行数据全部显示完毕即可结束显示子程序。
主程序核心部分如下:
int main()
{
Sys_Delay_Init(72);
Car_GPIO_Config();
Xunji_GPIO_Config();
Chaoshengbo_Init();
timer_Init();
TIM3_PWM_Init(2000);
while(1)
{
TIM3_PWMoutPA6_Config(1500);
TIM3_PWMoutPA7_Config(1500);
Chaoshengbo_ReadJuli();
if( juli>300)
{ Ctrl();}
else
{ Stop();}
}
}
电机PWM占空比设置核心程序如下:
//TIM3 Channel1 duty cycle = (TIM3_CCR1/ TIM3_ARR)* 100 = 50%
//TIM3 Channel2 duty cycle = (TIM3_CCR2/ TIM3_ARR)* 100 = 37.5%
//TIM3 Channel3 duty cycle = (TIM3_CCR3/ TIM3_ARR)* 100 = 25%
//TIM3 Channel4 duty cycle = (TIM3_CCR4/ TIM3_ARR)* 100 = 12.5%
void TIM3_PWMoutPA6_Config(u16 CCR1_Val)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
//使能通道1
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
// 使能TIM3重载寄存器ARR
}
void TIM3_PWMoutPA7_Config(u16 CCR2_Val)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//当定时器计数值小于CCR1_Val时为高电平
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
//使能通道2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
// 使能TIM3重载寄存器ARR
}
void TIM3_PWMoutPB0_Config( u16 CCR3_Val)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//当定时器计数值小于CCR1_Val时为高电平
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
//使能通道3
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
// 使能TIM3重载寄存器ARR
}
void TIM3_PWMoutPB1_Config(u16 CCR4_Val)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//当定时器计数值小于CCR1_Val时为高电平
TIM_OC4Init(TIM3, &TIM_OCInitStructure);
//使能通道4
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
// 使能TIM3重载寄存器ARR
}
超声波读距核心程序如下:
void Chaoshengbo_ReadJuli()
{
GPIO_SetBits(TRIG_PORT,TRIG_PIN);
//送>10US的高电平RIG_PORT,TRIG_PIN这两个在define中有
Delay_1us(20);
//延时20US
GPIO_ResetBits(TRIG_PORT,TRIG_PIN);
while(!GPIO_ReadInputDataBit(ECHO_PORT,ECHO_PIN)); //等待高电平
TIM_Cmd(TIM2,ENABLE); //开启时钟
while(GPIO_ReadInputDataBit(ECHO_PORT,ECHO_PIN)); //等待低电平
TIM_Cmd(TIM2, DISABLE); //定时器2失能
juli=(TIM_GetCounter(TIM2)*5*34/200);
//计算距离 juli=TIME/(计数频率)*(344/2)m
TIM_SetCounter(TIM2,0);
}
循迹功能核心程序如下:
void Ctrl()
{
u8 Temp=(u8)(GPIO_ReadInputData(GPIOB)&0xf0);
switch (Temp)
{
case 0x00:Go();
break;
case 0x10:Right();
break;
case 0x20:Right();
break;
case 0x30:Right();
break;
case 0xE0:Right();
break;
case 0xD0:Right();
break;
case 0x40:Left();
break;
case 0x80:Left();
break;
case 0xC0:Left();
break;
case 0x70:Left();
break;
case 0xB0:Left();
break;
case 0xF0:Stop();
break;
default:Back();
break;
}
Delay_1ms(100);
}
|