一、概要
主控采用stm32F103C8T6,三个循迹模块,超声波模块,openmv,降压模块,锂电池组,TT马达四个,L298n。可以实现循迹,避障,颜色识别等功能。
二、硬件设备
1、循迹模块
红外循迹模块通常包含一组红外线发射管和一组红外线接收器,发射管发出红外线,接收器接收地面反射的红外线信号。当小车在黑线上行驶时,黑线会吸收一部分红外线,接收器接收到的信号会变弱,当小车在白线上行驶时,反射的红外线信号比较强,接收器接收到的信号强度也比较高。
2、超声波模块
超声波模块是一种使用超声波进行测距的传感器模块。它由超声波发射器和接收器组成。当发射器发射一段超声波时,它会以音速的速度在空气中传播,直到遇到一个障碍物。障碍物会反射一部分超声波回来,被接收器接收到。
超声波模块会测量发射超声波和接收反射波之间的时间差,通过计算公式,转化为距离值。具体公式如下:
距离 = (时间差 × 音速) ÷ 2
其中,时间差是超声波从发射器到障碍物和从障碍物回到接收器所需的时间,音速是在空气中传播的声音速度,2是因为超声波在传播过程中需要往返两次。
3、openmv
OpenMV的原理是通过摄像头采集图像数据,然后进行实时的图像处理和分析。它可以识别人脸、二维码、颜色等特征,并支持多种通信协议,如USB、WiFi、UART等。
OpenMV使用Python语言进行编程,用户可以利用Python语言对实时图像进行处理、分析和控制。同时,它还提供了一系列丰富的图像处理库和算法,如卷积、滤波、边缘检测、二值化等。
4、L298n
L298N主要由两个H桥电路组成,每个H桥电路包括四个晶体管和四个反并联二极管,它们能够将外部控制信号转化为电机驱动信号。当控制信号为高电平时,H桥电路相应地将输出电压加到电机上,使其正转;当控制信号为低电平时,H桥电路输出电压为低电平,电机停止运转或反转。
L298N还具有过温保护、过流保护和低电压保护等功能,能有效保护电机和L298N本身。
四、实现原理
1、主控通过判断三个循迹模块输出电平实现赛道识别,从而控制电机转向等。
2、通过超声波模块判断障碍物与小车的距离。
3、通过主控与openmv建立通讯,实现颜色识别
五、代码部分
Motor:这个我用的是软件模拟的pwm波,小白级别的呆呆代码,有一点点长,定时器二就是正常配置,每到达自动重装值进入一次中断。
#include "stm32f10x.h" // Device header
#include "TIM2.h"
//引脚定义
#define Motor00 GPIO_ResetBits(GPIOA,GPIO_Pin_0)
#define Motor10 GPIO_ResetBits(GPIOA,GPIO_Pin_1)
#define Motor20 GPIO_ResetBits(GPIOA,GPIO_Pin_2)
#define Motor30 GPIO_ResetBits(GPIOA,GPIO_Pin_3)
#define Motor01 GPIO_SetBits(GPIOA,GPIO_Pin_0)
#define Motor11 GPIO_SetBits(GPIOA,GPIO_Pin_1)
#define Motor21 GPIO_SetBits(GPIOA,GPIO_Pin_2)
#define Motor31 GPIO_SetBits(GPIOA,GPIO_Pin_3)
static uint16_t Counter,FX,SD;
/**
* @brief 电机初始化
* @param 无
* @retval 无
*/
void Motor_Init(void)
{
TIM2_Init();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
/**
* @brief 电机设置运动方式
* @param b 要设置的速度(10 11 12)
* @param a 设置方向(参考遥控器)
* @retval 无
*/
void Motor_FXSD(unsigned char a,unsigned b)
{
FX=a;
SD=b;
}
//定时器2中断函数
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
Counter++;
Counter%=100;
if(FX==5)
{
Motor00;
Motor10;
Motor20;
Motor30;
}
if(SD==12)
{
if(FX==2)
{
if(Counter<50)
{
Motor01;
Motor10;
Motor21;
Motor30;
}
if(Counter>=50)
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
if(FX==8)
{
if(Counter<50)
{
Motor00;
Motor11;
Motor20;
Motor31;
}
if(Counter>=50)
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
if(FX==4)
{
if(Counter<50)
{
Motor00;
Motor10;
Motor21;
Motor30;
}
else
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
if(FX==6)
{
if(Counter<50)
{
Motor01;
Motor10;
Motor20;
Motor30;
}
else
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
if(FX==7)
{
if(Counter<50)
{
Motor00;
Motor10;
Motor20;
Motor31;
}
else
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
if(FX==9)
{
if(Counter<50)
{
Motor00;
Motor11;
Motor20;
Motor30;
}
else
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
}
if(SD==10)
{
if(FX==2)
{
if(Counter<60)
{
Motor01;
Motor10;
Motor21;
Motor30;
}
if(Counter>=60)
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
if(FX==8)
{
if(Counter<60)
{
Motor00;
Motor11;
Motor20;
Motor31;
}
if(Counter>=60)
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
if(FX==4)
{
if(Counter<30)
{
}
if(Counter>=30)
{
Motor00;
Motor10;
Motor21;
Motor30;
}
else
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
if(FX==6)
{
if(Counter<30)
{
Motor01;
Motor10;
Motor21;
Motor30;
}
if(Counter>=30)
{
Motor01;
Motor10;
Motor20;
Motor30;
}
else
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
if(FX==7)
{
if(Counter<60)
{
Motor00;
Motor10;
Motor20;
Motor31;
}
else
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
if(FX==9)
{
if(Counter<30)
{
Motor00;
Motor11;
Motor20;
Motor30;
}
else
{
Motor00;
Motor10;
Motor20;
Motor30;
}
}
}
if(SD==11)
{
if(FX==2)
{
Motor01;
Motor10;
Motor21;
Motor30;
}
if(FX==8)
{
Motor00;
Motor11;
Motor20;
Motor31;
}
if(FX==4)
{
if(Counter<30)
{
Motor01;
Motor10;
Motor21;
Motor30;
}
else
{
Motor00;
Motor10;
Motor21;
Motor30;
}
}
if(FX==6)
{
if(Counter<30)
{
Motor01;
Motor10;
Motor21;
Motor30;
}
else
{
Motor01;
Motor10;
Motor20;
Motor30;
}
}
if(FX==7)
{
if(Counter<30)
{
Motor00;
Motor11;
Motor20;
Motor31;
}
else
{
Motor00;
Motor10;
Motor20;
Motor31;
}
}
if(FX==9)
{
if(Counter<30)
{
Motor00;
Motor11;
Motor20;
Motor31;
}
else
{
Motor00;
Motor11;
Motor20;
Motor30;
}
}
}
}
}
HC:非常难受,我复制粘贴的乱码了
#include "stm32f10x.h" // Device header
#include "Delay.h"
u32 Distance; //³¬Éù²¨²â¾à
TIM_ICInitTypeDef ICInitStructure;
/**************************************************************************
º¯Êý¹¦ÄÜ£º¶¨Ê±Æ÷3ͨµÀ3ÊäÈ벶»ñ³õʼ»¯
Èë¿Ú²ÎÊý£ºÈë¿Ú²ÎÊý£ºarr£º×Ô¶¯ÖØ×°Öµ psc£ºÊ±ÖÓÔ¤·ÖƵÊý
·µ»Ø Öµ£ºÎÞ
**************************************************************************/
void TIM3_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure; //¶¨Òå½á¹¹ÌåGPIO_InitStructure
NVIC_InitTypeDef NVIC_InitStructure; //¶¨Òå½á¹¹NVIC_InitStructure
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //¶¨Òå½á¹¹TIM_TimeBaseStructure
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //¿ªÆôTIM3BʱÖÓ
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //¿ªÆôGPIOBʱÖÓ
//GPIOB.0
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PB0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //ÏÂÀÊäÈë
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO¿ÚËÙ¶È
GPIO_Init(GPIOB, &GPIO_InitStructure); //GBIOB³õʼ»¯
GPIO_ResetBits(GPIOB,GPIO_Pin_0); //PA0 ÏÂÀ
//GPIOB.1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PB1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //ÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO¿ÚËÙ¶È
GPIO_Init(GPIOB, &GPIO_InitStructure); //GBIOB³õʼ»¯
TIM_TimeBaseStructure.TIM_Period = arr; //ÉèÖÃÔÚÏÂÒ»¸ö¸üÐÂʼþ×°Èë»î¶¯µÄ×Ô¶¯ÖØ×°ÔؼĴæÆ÷ÖÜÆÚµÄÖµ ¼ÆÊýµ½5000Ϊ500ms
TIM_TimeBaseStructure.TIM_Prescaler =psc; //ÉèÖÃÓÃÀ´×÷ΪTIMxʱÖÓƵÂʳýÊýµÄÔ¤·ÖƵֵ 10KhzµÄ¼ÆÊýƵÂÊ
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //ÉèÖÃʱÖÓ·Ö¸î:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIMÏòÉϼÆÊýģʽ
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //¸ù¾ÝTIM_TimeBaseInitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯TIMxµÄʱ¼ä»ùÊýµ¥Î»
//³õʼ»¯TIM3ÊäÈ벶»ñ²ÎÊý
ICInitStructure.TIM_Channel = TIM_Channel_3; //CC3S=01 Ñ¡ÔñÊäÈë¶Ë IC3Ó³Éäµ½TI3ÉÏ
ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //ÉÏÉýÑز¶»ñ
ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //Ó³Éäµ½TI3ÉÏ
ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //ÅäÖÃÊäÈë·ÖƵ,²»·ÖƵ
ICInitStructure.TIM_ICFilter = 0x00;//IC3F=0000 ÅäÖÃÊäÈëÂ˲¨Æ÷ ²»Â˲¨
TIM_ICInit(TIM3, &ICInitStructure);
//TIM3 NVIC ÅäÖÃ
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3ÖжÏ
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//ÇÀÕ¼ÓÅÏȼ¶2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //×ÓÓÅÏȼ¶0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀʹÄÜ
NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷
TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_CC3,ENABLE);//ÔÊÐí¸üÐÂÖÐ¶Ï ,ÔÊÐíCC3IE²¶»ñÖжÏ
TIM_Cmd(TIM3,ENABLE ); //ʹÄܶ¨Ê±Æ÷3
}
u8 TIM3CH3_CAPTURE_STA=0; //ÊäÈ벶»ñ״̬
u16 TIM3CH3_CAPTURE_VAL; //ÊäÈ벶»ñÖµ
/**************************************************************************
º¯Êý¹¦ÄÜ£º³¬Éù²¨½ÓÊջز¨º¯Êý
Èë¿Ú²ÎÊý£ºÎÞ
·µ»Ø Öµ£ºÎÞ
**************************************************************************/
/*¾àÀëdistance = v*t
ÒôËÙv=340m/s=340mm/ms =0.340mm/us£¬1ms=1000us
¾àÀë=£¨Ê±¼ä£¨Î¢Ã룩* 340/1000£©/2
2ÊÇÒòΪtÊÇÀ´»Øʱ¼ä
*/
void Read_Distane(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_1); // ¸ßµçƽ
Delay_us(15);
GPIO_ResetBits(GPIOB, GPIO_Pin_1); // µÍµçƽ
if(TIM3CH3_CAPTURE_STA&0X80)//³É¹¦²¶»ñµ½ÁËÒ»´Î¸ßµçƽ
{
Distance=TIM3CH3_CAPTURE_STA&0X3F;
Distance*=65536; //Òç³öʱ¼ä×ܺÍ
Distance+=TIM3CH3_CAPTURE_VAL; //µÃµ½×ܵĸߵçƽʱ¼ä
// printf("³¬Éù²¨Ì½²âÀ´»Øʱ¼ä=%d us\r\n",Distance);
Distance=Distance*340/1000/2;
TIM3CH3_CAPTURE_STA=0; //¿ªÆôÏÂÒ»´Î²¶»ñ
}
}
/**************************************************************************
º¯Êý¹¦ÄÜ£º³¬Éù²¨»Ø²¨Âö¿í¶ÁÈ¡ÖжÏ
Èë¿Ú²ÎÊý£ºÎÞ
·µ»Ø Öµ£ºÎÞ
**************************************************************************/
void TIM3_IRQHandler(void)
{
if((TIM3CH3_CAPTURE_STA&0X80)==0)//»¹Î´³É¹¦²¶»ñ
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
if(TIM3CH3_CAPTURE_STA&0X40)//ÒѾ²¶»ñµ½¸ßµçƽÁË
{
if((TIM3CH3_CAPTURE_STA&0X3F)==0X3F)//¸ßµçƽ̫³¤ÁË
{
TIM3CH3_CAPTURE_STA|=0X80;//±ê¼Ç³É¹¦²¶»ñÁËÒ»´Î
TIM3CH3_CAPTURE_VAL=0XFFFF;
}else TIM3CH3_CAPTURE_STA++; //¶¨Ê±Æ÷Òç³öTIM3CH3_CAPTURE_STA¼Ó1¼ÆÊý
}
}
if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)//²¶»ñ3·¢Éú²¶»ñʼþ
{
if(TIM3CH3_CAPTURE_STA&0X40) //²¶»ñµ½Ò»¸öϽµÑØ
{
TIM3CH3_CAPTURE_STA|=0X80; //±ê¼Ç³É¹¦²¶»ñµ½Ò»´ÎÉÏÉýÑØ
TIM3CH3_CAPTURE_VAL=TIM_GetCapture3(TIM3); //»ñÈ¡¶¨Ê±Æ÷3ͨµÀ3µÄµÍµçƽÐźÅ
TIM_OC3PolarityConfig(TIM3,TIM_ICPolarity_Rising); //CC1P=0 ÉèÖÃΪÉÏÉýÑز¶»ñ
}else //»¹Î´¿ªÊ¼,µÚÒ»´Î²¶»ñÉÏÉýÑØ
{
TIM3CH3_CAPTURE_STA=0; //Çå¿Õ
TIM3CH3_CAPTURE_VAL=0;
TIM_SetCounter(TIM3,0);
TIM3CH3_CAPTURE_STA|=0X40; //±ê¼Ç²¶»ñµ½ÁËÉÏÉýÑØ
TIM_OC3PolarityConfig(TIM3,TIM_ICPolarity_Falling); //CC1P=1 ÉèÖÃΪϽµÑز¶»ñ
}
}
}
TIM_ClearITPendingBit(TIM3, TIM_IT_CC3|TIM_IT_Update); //Çå³ýÖжϱê־λ
}
USART:一定要记得共地。
#include "stm32f10x.h" // Device header
uint16_t res=1,count;
void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStrucyure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitStrucyure.USART_BaudRate = 9600;
USART_InitStrucyure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStrucyure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStrucyure.USART_Parity = USART_Parity_No;
USART_InitStrucyure.USART_StopBits = USART_StopBits_1;
USART_InitStrucyure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1,&USART_InitStrucyure);
USART_Cmd(USART1,ENABLE);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStructure);
}
uint16_t USART1_Get(void)
{
count=res;
res=0;
return count;
}
void USART1_IRQHandler(void)
{
if(USART_GetFlagStatus(USART1,USART_IT_RXNE)!=RESET)
{
res=USART_ReceiveData(USART1);
}
}
循迹模块:就是判断一下高低电平非常简单
#include "stm32f10x.h" // Device header
#include "Delay.h"
uint16_t Count,L0,L1,R2,R3;
void TCRT5000_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
uint16_t TCRT5000_L0(void)
{
return GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12);
}
uint16_t TCRT5000_L1(void)
{
return GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13);
}
uint16_t TCRT5000_R2(void)
{
return GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14);
}
uint16_t TCRT5000_R3(void)
{
return GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15);
}
main:文章来源:https://www.toymoban.com/news/detail-728540.html
#include "stm32f10x.h" // Device header
#include "Motor.h"
#include "TCRT5000.h"
#include "OLED.h"
#include "HC.h"
#include "Delay.h"
#include "USART1.h"
extern u32 Distance;
uint32_t c='v',i,a,L,R,m,b;
int main(void)
{
Motor_Init();
OLED_Init();
Delay_ms(1000);
USART1_Init();
TCRT5000_Init();
TIM3_Cap_Init(0XFFFF,72-1);//TIM_CH3ÊäÈ벶»ñ
while (1)
{
c=USART1_Get();
OLED_ShowNum(2,1,c,2);
if(c==49)
{
Motor_FXSD(5,11);
Delay_ms(3000);
}
c=0;
Distance=500;
Read_Distane();
OLED_ShowNum(1,1,Distance,5);
if(a<1)
{
if(L==0)
{
if(Distance<200)
{
if(i==0)
{
Motor_FXSD(8,10);
Delay_ms(100);
Motor_FXSD(4,10);
while(TCRT5000_R3()==1);
Motor_FXSD(6,10);
Delay_ms(750);
i=3;
R=5;
L=5;
}
}
}
}
Distance=500;
Read_Distane();
OLED_ShowNum(1,1,Distance,5);
if(i<1)
{
if(R==5)
{
if(Distance<200)
{
if(a==0)
{
Motor_FXSD(8,10);
Delay_ms(100);
Motor_FXSD(6,10);
while(TCRT5000_L0()==1);
Motor_FXSD(4,10);
Delay_ms(750);
a=3;
L=0;
R=0;
}
}
}
}
if(i>0)
{
i--;
}
if(a>0)
{
a--;
}
if(TCRT5000_L0()==1&&TCRT5000_R2()==1&&TCRT5000_R3()==1)
{
Motor_FXSD(2,10);
Delay_ms(1);
}
if(TCRT5000_R3()==0)
{
Motor_FXSD(8,10);
Delay_ms(130);
Motor_FXSD(4,12);
Delay_ms(400);
}
if(TCRT5000_R2()==0)
{
Motor_FXSD(8,10);
Delay_ms(130);
Motor_FXSD(4,12);
Delay_ms(400);
}
if(TCRT5000_L0()==0)
{
Motor_FXSD(8,10);
Delay_ms(30);
Motor_FXSD(6,12);
Delay_ms(60);
}
}
}
源文件已上传,有需要的同学可以参考一下,我也是个萌新,代码比较简单,希望可以给同学们提供一些便利。文章来源地址https://www.toymoban.com/news/detail-728540.html
到了这里,关于STM32循迹避障小车(颜色识别)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!