STM32循迹避障小车(颜色识别)
文章目录
- 一、概要
- 二、硬件设备
- 1、循迹模块
- 2、超声波模块
- 3、openmv
- 4、L298n
- 四、实现原理
- 五、代码部分
一、概要
主控采用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_InitStructureNVIC_InitTypeDef NVIC_InitStructure; //¶¨Òå½á¹¹NVIC_InitStructureTIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //¶¨Òå½á¹¹TIM_TimeBaseStructureRCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //¿ªÆôTIM3BʱÖÓRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //¿ªÆôGPIOBʱÖÓ//GPIOB.0GPIO_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.1GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PB1GPIO_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Ϊ500msTIM_TimeBaseStructure.TIM_Prescaler =psc; //ÉèÖÃÓÃÀ´×÷ΪTIMxʱÖÓÆµÂʳýÊýµÄÔ¤·ÖƵֵ 10KhzµÄ¼ÆÊýƵÂÊ TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //ÉèÖÃʱÖÓ·Ö¸î:TDTS = Tck_timTIM_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 ;//ÇÀÕ¼ÓÅÏȼ¶2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //×ÓÓÅÏȼ¶0NVIC_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 headeruint16_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:
#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);}}
}
源文件已上传,有需要的同学可以参考一下,我也是个萌新,代码比较简单,希望可以给同学们提供一些便利。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
